基本同步原语:
sync.Mutex:用于保护临界区域的互斥锁,例如:
var mu sync.Mutex
var count int
func increment() {
mu.Lock()
defer mu.Unlock()
count++
}
sync.RWMutex:用于允许多个读操作和单个写操作的读写锁,例如:
var rwmu sync.RWMutex
var data map[string]string
func read(key string) string {
rwmu.RLock()
defer rwmu.RUnlock()
return data[key]
}
func write(key, value string) {
rwmu.Lock()
defer rwmu.Unlock()
data[key] = value
}
sync.WaitGroup:用于等待一组并发操作完成的同步工具,例如:
var wg sync.WaitGroup
func main() {
urls := []string{"https://google.com", "https://bing.com", "https://yahoo.com"}
for _, url := range urls {
wg.Add(1)
go fetch(url)
}
wg.Wait()
fmt.Println("All done")
}
func fetch(url string) {
defer wg.Done()
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(resp.Status)
}
sync.Once:用于只执行一次的初始化操作,例如:
var once sync.Once
var db *sql.DB
func getDB() *sql.DB {
once.Do(func() {
db = sql.Open("mysql", "user:password@/dbname")
})
return db
}
sync.Cond:用于在满足某些条件时通知或等待其他 goroutine 的同步工具。
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Mutex
c := sync.NewCond(&m) // 创建一个条件变量,关联互斥锁m
queue := make([]int, 0, 10)
// 生产者
producer := func(i int) {
m.Lock() // 获取互斥锁
defer m.Unlock()
queue = append(queue, i) // 向队列中添加元素
fmt.Println("producer:", i)
c.Signal() // 发送信号给消费者
}
// 消费者
consumer := func(i int) {
m.Lock() // 获取互斥锁
for len(queue) == 0 { // 如果队列为空,则等待信号
c.Wait()
}
item := queue[0] // 取出队列中的第一个元素
queue = queue[1:]
fmt.Println("consumer:", i, item)
m.Unlock() // 释放互斥锁
}
for i := 0; i < 10; i++ {
go producer(i)
go consumer(i)
}
}
高级同步原语:
sync.Map:用于并发安全地存储键值对的映射类型,例如:
var m sync.Map
func main() {
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
m.Store("foo", "bar")
}()
go func() {
defer wg.Done()
m.Store("baz", "qux")
}()
wg.Wait()
m.Range(func(key, value interface{}) bool {
fmt.Println(key, value)
return true
})
}
sync.Pool:用于缓存和复用临时对象的池类型,例如:
type Buffer struct {
buf []byte
}
var pool = &sync.Pool{
New: func() interface{} {
return &Buffer{}
},
}
func main() {
b := pool.Get().(*Buffer)
b.buf = append(b.buf, []byte("hello")...)
fmt.Println(string(b.buf))
pool.Put(b)
}
sync/atomic 包:提供了一些原子操作函数,可以在不使用锁的情况下对整数、指针等进行安全地读写、增减、交换和比较。例如:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int64 = 0 // 定义一个 int64 类型的变量 counter,初始值为0
var wg sync.WaitGroup // 定义一个 WaitGroup 变量 wg,用于等待所有 goroutine 完成
wg.Add(10) // 设置 wg 的计数器为10,表示有10个 goroutine 需要等待
for i := 0; i < 10; i++ { // 启动10个 goroutine 来并发地增加 counter 的值
go func() { // 每个 goroutine 中执行以下操作
defer wg.Done() // 函数结束时通知 wg 计数器减一
for j := 0; j < 10000; j++ { // 循环10000次
atomic.AddInt64(&counter, 1) // 原子地将 counter 加一
}
}()
}
wg.Wait() // 等待所有 goroutine 完成
fmt.Println(counter) // 输出 counter 的最终值,应该是100000
}