返回
探索 Go 协程间的通信:利用共享变量
后端
2023-11-04 13:00:16
在 Go 中,协程是轻量级线程,可以同时执行多个任务。协程间通信是并发编程中的一个关键方面。在本文中,我们将探索利用共享变量实现协程间通信的方法。
共享变量
协程可以通过共享变量进行通信。当一个协程修改共享变量时,其他协程会看到这些修改。但是,共享变量需要小心使用,因为多个协程同时访问共享变量可能会导致数据竞争。
数据互斥
为了防止数据竞争,我们需要确保只有一个协程在给定的时间点访问共享变量。我们可以通过互斥锁或通道来实现数据互斥。
互斥锁
互斥锁是一种机制,它允许一次只有一个协程访问共享变量。当一个协程获取互斥锁时,其他协程将被阻止,直到该协程释放互斥锁。
import (
"sync"
"time"
)
var (
counter int
mu sync.Mutex
)
func main() {
for i := 0; i < 10; i++ {
go func(i int) {
mu.Lock()
counter++
time.Sleep(time.Second)
mu.Unlock()
}(i)
}
time.Sleep(11 * time.Second)
fmt.Println(counter) // 输出:10
}
通道
通道是另一种实现数据互斥的方法。通道是一个 FIFO 队列,协程可以通过发送或接收数据进行通信。当一个协程发送数据时,它将被放入通道中。当另一个协程接收数据时,它将从通道中取出数据。
import (
"sync"
)
var (
counter int
ch = make(chan struct{})
mu sync.Mutex
)
func main() {
for i := 0; i < 10; i++ {
go func(i int) {
mu.Lock()
ch <- struct{}{}
mu.Unlock()
counter++
<-ch
}(i)
}
time.Sleep(11 * time.Second)
fmt.Println(counter) // 输出:10
}
避免循环依赖
当多个协程通过共享变量进行通信时,可能会出现循环依赖。例如,如果协程 A 发送数据给协程 B,而协程 B 依赖于协程 A 完成某些操作,则可能会导致死锁。
为了避免循环依赖,我们应该设计我们的程序,以便协程之间的通信呈单向流动。例如,协程 A 可以向协程 B 发送数据,但协程 B 不应向协程 A 发送数据。
结论
在 Go 中,利用共享变量实现协程间通信是一种简单而有效的技术。但是,重要的是要小心处理数据竞争,并避免循环依赖。通过正确使用互斥锁或通道,我们可以确保协程间通信安全且高效。