一,Goroutine
什么是goroutine?
goroutine是Go语言中的一种轻量级线程,它可以在单个线程中运行,并且可以由Go语言的运行时系统进行调度。goroutine的启动非常快,只需要几个字节的栈空间,因此可以并发地启动大量的goroutine,从而实现高效的并发编程。在Go语言中,使用关键字go可以启动一个goroutine。
这也是go语言适合高并发的一个主要原因。
如何使用goroutine?
基本用法就是在函数的前面加一个go关键字,就可以为该函数创建一个协程
接下来是一个测试代码,简述了goroutine的基本使用方法
package main
import (
"fmt"
"time"
)
func main() {
// 启动一个goroutine来执行计算任务
go compute()
// 在主goroutine中执行其他任务
for i := 0; i < 10; i++ {
fmt.Println("Main goroutine is working...")
time.Sleep(time.Millisecond * 500)
}
}
func compute() {
// 在新的goroutine中执行计算任务
for i := 0; i < 5; i++ {
fmt.Println("Compute goroutine is working...")
time.Sleep(time.Millisecond * 500)
}
}
在这个例子中,我们启动了一个新的goroutine来执行计算任务,同时在主goroutine中执行其他任务。执行结果如下
可以看出子协程与主协程是并行执行的。
注意: time.Sleep(time.Millisecond * 500)的作用是让当前协程秀逸休息一段时间,以便给其他协程执行机会。
二,channel
goroutine间的通信(csp)有两种,但go更加推荐第一种,也就是通过通信共享内存,在通信中就需要用到channel,channel的基本用法如下:
在Go语言中,channel是一种原生类型,用于goroutine之间的通信和同步。channel可以看作是一条管道,goroutine可以通过它发送和接收数据。channel有两个基本操作:发送和接收。发送操作使用<-符号,例如:
ch <- data // 将数据data发送到channel ch中接收操作使用<-符号,例如:data := <- ch // 从channel ch中接收数据,并将其保存到变量data中channel可以是有缓冲的,也可以是无缓冲的。无缓冲的channel在发送和接收时会被阻塞,直到另一个goroutine准备好接收或发送数据。有缓冲的channel则可以在缓冲区未满时发送数据,或在缓冲区未空时接收数据,否则也会被阻塞。 通过使用channel,我们可以实现goroutine之间的通信和同步,从而实现更加高效和安全的并发编程。例如,我们可以使用channel来实现生产者-消费者模式,或者实现多个goroutine之间的任务协作。
channel的创建需要使用make关键字,有如下两种形式,一种是创建带缓冲区的channel,一种是创建不带缓冲区的channel。
无缓冲通道 make(chan int)
有缓冲通道 make(chan int,2)
以下例子是一个关于channel的使用实例
package main
import "fmt"
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 1; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
fmt.Println(i)
}
}
func main() {
CalSquare()
}
两个协程之间通过src完成了通信
并发安全Lock
Mutex是Go语言中的一个同步原语,用于实现互斥锁,即一次只能有一个协程访问共享资源。Mutex的全称是Mutual Exclusion,意为互斥。 在Go语言中,多个协程可以同时运行,如果多个协程同时访问共享资源,可能会导致数据竞争和不确定的行为。为了避免这种情况,我们可以使用Mutex来保护共享资源。 Mutex的使用非常简单,可以通过sync包中的Mutex类型来创建一个互斥锁,然后使用Lock和Unlock方法来加锁和解锁。
相关代码
/*
*
准备开启多个这样的协程,通过上锁,开锁,使各个协程互不干扰
*/
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x += 1
}
}
func Add() {
x = 0
for i := 0; i < 5; i++ {
go addWithLock()
}
time.Sleep(time.Second)
println("WithLock", x)
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
println("WithoutLock", x)
}
func main() {
//CalSquare()
Add()
}