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)