Go 语言并发同步的方式
Golang Sync 包提供了同步原语,例如:
-
mutex
-
Waitgroup
-
Pool
-
Read
-
Write mutex
- condition variables条件变量
锁
sync.Mutex
提供了一个互斥原语,它允许共享资源的互斥,防止竞争条件。
package main
import (
"sync"
)
func main() {
i := 10
mutex := &sync.Mutex{}
mutex.Lock()
i++
mutex.Unlock()
}
读写锁
sync.RWMutex
提供读写锁,它提供了与原始互斥锁类似的方法,但可以使用 RLock
和 RUnlock
方法允许并发读取:
package main
import (
"sync"
)
func main() {
i := 10
mutex := &sync.RWMutex{}
mutex.Lock()
// only one goroutine can access this code at a time
i++
mutex.Unlock()
mutex.RUnlock()
i++ // concurrent reads
mutex.RUnlock()
}
上一个示例可以允许多个 goroutine 读取代码。与 sync.Mutex
不同,它一次只允许一个读取器和一个写入器。
Waitgroups
sync.Waitgroup
用于为 goroutine 提供阻塞机制。使用 Waitgroup,您可以阻止函数的执行,直到所有 goroutine 执行完毕。
它通过创建一个计数器来工作,该计数器保存要等待的 goroutine 的数量。一旦一个 goroutine 完成,计数器减 1。一旦计数器为 0,Waitgroup 就会解除对执行的阻塞。
要将值添加到 Waitgroup 计数器,我们可以使用 Add()
方法,该方法采用整数值。
要在完成后从计数器中删除一个 goroutine,我们使用 Done()
方法。例如:
package main
import (
"fmt"
"sync"
)
func main() {
wg := &sync.WaitGroup{}
for i := 0; i < 5; i++ {
wg.Add(1)
go func(x int) {
fmt.Printf("Worker: %d running\n", x)
wg.Done()
}(i)
}
wg.Wait()
}
在前面的示例中,我们通过使用 Add()
函数将 Waitgroup 计数器的值加 1。
一旦一个 goroutine 完成,我们使用 Done()
方法将计数器减 1。前面的代码应返回输出为:
Worker: 3 running
Worker: 1 running
Worker: 4 running
Worker: 0 running
Worker: 2 running
Once
sync.Once
原语确保一个函数只运行一次。一个例子如下所示:
package main
import (
"fmt"
"sync"
)
func main() {
var once sync.Once
RunOnce := func() {
fmt.Println("Run once")
}
done := make(chan string)
for i := 0; i < 5; i++ {
go func() {
once.Do(RunOnce)
done <- "Hi"
}()
}
for i := 0; i < 5; i++ {
<-done
}
}
运行该代码:
Run once
总结
本文涵盖了 Go sync 包提供的一些基本方法:如互斥锁、读写锁、等待组、Once 等同步原语的用法。更多原理和使用方法等待读者去探索。