保存和复用临时对象,减少内存分配,降低 GC 压力。[2]
声明对象池,只需要实现 New 函数即可。对象池中没有对象时,将会调用 New 函数创建。
- var studentPool = sync.Pool{
- New: func() interface{} {
- return new(Student)
- },
- }
- stu := studentPool.Get().(*Student)
- json.Unmarshal(buf, stu)
- studentPool.Put(stu)
Get() 用于从对象池中获取对象,因为返回值是 interface{},因此需要类型转换。Put() 则是在对象使用完毕后,返回对象池。
Go 标准库提供的使函数只执行一次的实现,常应用于单例模式,例如初始化配置、保持数据库连接等[2]
sync.Cond条件变量用来协调想要访问共享资源的那些 goroutine,当共享资源的状态发生变化的时候,它可以用来通知被互斥锁阻塞的 goroutine。[2]
Go语言中sync库提供了两种锁互斥锁(sync.Mutex)和读写锁(sync.RWMutex)
互斥锁,互斥即不可同时运行。即使用了互斥锁的两个代码片段互相排斥,只有其中一个代码片段执行完成后,另一个才能执行。
Go 标准库中提供了 sync.Mutex 互斥锁类型及其两个方法:
读写锁,分为读锁和写锁,读锁是允许同时执行的,但写锁是互斥的。一般来说,有如下几种情况:
Go 标准库中提供了 sync.RWMutex 读写锁类型及其四个方法:
读写锁的存在是为了解决读多写少时的性能问题,读场景较多时,读写锁可有效地减少锁阻塞的时间。
假设每个读写操作为1微妙
读写比为 9:1 时,读写锁的性能约为互斥锁的 8 倍
读写比为 1:9 时,读写锁性能相当
读写比为 5:5 时,读写锁的性能约为互斥锁的 2 倍[2]
相比于数据类型map,sync.Map是一个并发安全的map
Go标准库中的Map提供了六个方法
Delete(key any) 删除key
Load(key any) (value any, ok bool) 读取key
LoadAndDelete(key any) (value any, loaded bool) 读取并删除
LoadOrStore(key, value any) (actual any, loaded bool) 读取,不存在则存储
Range(f func(key, value any) bool) 遍历MAP
Store(key, value any) 存储key,value
WaitGroup就是package sync用来做任务编排的一个并发原语。这个要解决的就是并发-等待的问题
Go标准库中的WaitGroup提供了三个方法
- func main() {
- var wg sync.WaitGroup
- wg.Add(10)
- wg.Add(-10)// 将-10作为参数调用Add,计数值被设置为0
- wg.Add(-1)//panic
- }
- func main() {
- var wg sync.WaitGroup
- wg.Add(1)
- wg.Done()
- wg.Done()
- }
使用WaitGroup一定要遵守的原则就是,等所有的Add方法调用之后再调用Wait,否则就可能导致panic或者不期望的结果
WaitGroup 是可以重用的。只要 WaitGroup 的计数值恢复到零值的状态
- func main() {
- var wg sync.WaitGroup
- wg.Add(1)
- go func() {
- time.Sleep(time.Millisecond)
- wg.Done() // 计数器减1
- wg.Add(1) // 计数值加1
- }()
- wg.Wait() // 主goroutine等待,有可能和第7行并发执行
- }