1. 介绍 文档地址:https://pkg.go.dev/sync Go 标准库 sync 用于提供基础的同步原语,如互斥锁、Once、WaitGroup,而更高层级的同步更推荐使用通道来完成。 使用 Once 来定义只会执行一次的操作: var once sync.Once onceFunc := func() { fmt.Println("Only once") } for i := 0; i < 10; i++ { once.Do(onceFunc) } 使用 WaitGroup 来等待多个协程的完成: var wg sync.WaitGroup var urls = []string{ "http://www.golang.org/", "http://www.google.com/", "http://www.example.com/", } for _, url := range urls { wg.Add(1) go func(url string) { defer wg.Done() http.Get(url) }(url) } wg.Wait() 使用 Mutex 来添加互斥锁,防止不同协程间同时修改一个变量的值: var wg sync.WaitGroup var m sync.Mutex func Add(a *int) { m.Lock() defer m.Unlock() defer wg.Done() *a++ } func main() { var a int for i := 0; i < 100; i++ { wg.Add(1) go Add(&a) } wg.Wait() fmt.Printf("a=%d\n", a) } 2. 类型 2.1 Once 一个 Once 对象只会执行最多一次 Do 方法的函数,即使多次调用 Do 方法的参数是不同的函数。该结构体一般涌来做只做一次的初始化工作。 类型定义: type Once struct { // contains filtered or unexported fields } 方法: // Do 执行最多一次参数函数 func (o *Once) Do(f func()) 2.2 WaitGroup WaitGroup 用于等待多个协程的完成。每创建一个协程时调用 Add 方法来添加计数,每个协程完成后调用 Done 方法减少计数,Wait 方法则会阻塞直至所有计数清零。 类型定义: type WaitGroup struct { // contains filtered or unexported fields } 方法: // Add 添加计数 func (wg *WaitGroup) Add(delta int) // Done 计数减1 func (wg *WaitGroup) Done() // Wait 阻塞直至计数为0 func (wg *WaitGroup) Wait() 2.3 Mutex 互斥锁,任何时间最多只支持一个地方获得锁。不与任何协程绑定,可以在不同协程间上锁和解锁,来控制程序执行流程。 类型定义: type Mutex struct { // contains filtered or unexported fields } 方法: // Lock 上锁,如果对象已经上锁,则阻塞至可用 func (m *Mutex) Lock() // TryLock 尝试上锁,返回是否成功 func (m *Mutex) TryLock() bool // Unlock 解锁,对未上锁的互斥锁解锁会报错 func (m *Mutex) Unlock() 2.4 RWMutex 读写互斥锁,支持任意数量的读锁或者一个写锁。 类型定义: type RWMutex struct { // contains filtered or unexported fields } 方法: // Lock 上写锁,若已经有读锁或写锁则阻塞 func (rw *RWMutex) Lock() // TryLock 尝试上写锁,返回是否成功 func (rw *RWMutex) TryLock() bool // RLock 上读锁 func (rw *RWMutex) RLock() // TryRLock 尝试上读锁,返回是否成功 func (rw *RWMutex) TryRLock() bool // Unlock 解写锁 func (rw *RWMutex) Unlock() // RUnlock 解读锁 func (rw *RWMutex) RUnlock() // RLocker 返回一个 Locker 接口对象 func (rw *RWMutex) RLocker() Locker 2.5 Pool Pool 是一系列临时对象的读取和保存,对于多协程同步使用是安全的,主要用于缓存申请了而未使用的临时对象,以便后续使用,减轻垃圾回收的压力。成员变量 New 是一个返回 any 类型的函数,应该返回指针类型,这样作为 interface 值返回的时候就不需要申请内存了。 类型定义: type Pool struct { // New optionally specifies a function to generate // a value when Get would otherwise return nil. // It may not be changed concurrently with calls to Get. New func() any // contains filtered or unexported fields } 方法: // Put 将变量加到池子 func (p *Pool) Put(x any) // Get 从池子移除任意一个变量并返回 func (p *Pool) Get() any 2.6 Locker Locker 是一个接口,表示可以被上锁和解锁的对象。 类型定义: type Locker interface { Lock() Unlock() } 2.7 Cond Cond 是一个可供多个协程等待和触发事件的条件变量。关联的 Locker 变量通常是一个 Mutex 或 RWMutex。 类型定义: type Cond struct { // L is held while observing or changing the condition L Locker // contains filtered or unexported fields } 方法: // NewCond 创建对象 func NewCond(l Locker) *Cond // Broadcast 唤醒所有等待变量的协程 func (c *Cond) Broadcast() // Signal 唤醒一个等待变量的协程 func (c *Cond) Signal() // Wait 解锁 L 并阻塞等待当前协程 func (c *Cond) Wait() 2.8 Map 协程安全的 Map。 类型定义: type Map struct { // contains filtered or unexported fields } 方法: // CompareAndDelete 如果 key 对应的 value 等于 old,则删除对应 key func (m *Map) CompareAndDelete(key, old any) (deleted bool) // CompareAndSwap 如果 key 对应的 value 等于 old,则设置为 new func (m *Map) CompareAndSwap(key, old, new any) bool // Store 设置 key/value func (m *Map) Store(key, value any) // Load 返回 key 对应的 value func (m *Map) Load(key any) (value any, ok bool) // Swap 将 key 对应的 value 替换为参数的,并返回之前的 value func (m *Map) Swap(key, value any) (previous any, loaded bool) // LoadOrStore 如果 key 存在则返回对应的 value,否则设置参数的 value 并返回 func (m *Map) LoadOrStore(key, value any) (actual any, loaded bool) // LoadAndDelete 删除 key 并返回对应的 value func (m *Map) LoadAndDelete(key any) (value any, loaded bool) // Delete 删除 key func (m *Map) Delete(key any) // Range 对每个 key/value 调用指定函数 func (m *Map) Range(f func(key, value any) bool) 3. 函数 // OnceFunc 返回一个函数,该函数调用多少次都只会调用参数函数一次 func OnceFunc(f func()) func() // OnceValue 返回一个返回某变量的函数,该函数调用多少次都只会调用参数函数一次 func OnceValue[T any](f func() T) func() T // OnceValues 返回一个返回某两变量的函数,该函数调用多少次都只会调用参数函数一次 func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2)