go协程同步
Go语言提供了多种机制来同步goroutines,确保并发程序的正确性和效率。
Go语言中用于goroutine同步的几种主要方式:
WaitGroup
sync.WaitGroup是用来等待一组goroutines完成的主要方式。
通过WaitGroup的Add方法来设定需要等待的goroutines数量,Done方法表示一个goroutine完成了它的工作,而Wait方法则阻塞调用它的goroutine,直到计数器为零。
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
// 执行任务
fmt.Println("Goroutine", i, "finished")
}(i)
}
wg.Wait() // 等待所有goroutine完成
fmt.Println("All goroutines finished")
Mutex(互斥锁)
sync.Mutex提供了一种保护共享资源的方式。
通过互斥锁,可以确保在任何时刻只有一个goroutine能访问该资源, 防止了并发写入导致的数据竞态。
var mu sync.Mutex
var counter int
func increment() {
mu.Lock()
defer mu.Unlock()
counter++
}
// 在goroutines中调用increment
3. RWMutex(读写锁)
sync.RWMutex是一种特殊的互斥锁,它允许多个goroutine同时读取一个资源,但写入时则需要独占锁。这在读多写少的场景下非常有用,可以提高程序的并发性能。
go
var rwMu sync.RWMutex
var data int
func readData() int {
rwMu.RLock()
defer rwMu.RUnlock()
return data
}
func writeData(value int) {
rwMu.Lock()
defer rwMu.Unlock()
data = value
}
- Channel
Channel是Go中实现goroutine之间通信的主要方式,同时它也可以用于同步。
例如,可以使用无缓冲的channel实现信号通知,确保特定事件的顺序。
done := make(chan bool)
go func() {
// 执行任务
fmt.Println("Goroutine finished work")
done <- true // 发送完成信号
}()
<-done // 等待接收信号
fmt.Println("Main goroutine received signal")
- Context
context.Context类型用于控制goroutine的生命周期。它可以用来发送取消信号,可以优雅地取消正在执行的goroutine。
ctx, cancel := context.WithCancel(context.Background())
go func() {
select {
case <-ctx.Done():
fmt.Println("Goroutine canceled")
return
default:
// 执行正常逻辑
}
}()
// 当需要取消goroutine时
cancel()
在实际开发中,合理选择和组合这些机制,可以构建出既安全又高效的并发程序。