十一 同步模式
Sync.WaitGroup 同步屏障
可以达到并发goroutine的执行屏障的效果,提供了用于创建等待多个并发执行的代码块在达到WaitGroup显式指定的同步条件后,才可继续执行wait调用后的后续代码能力
Add和Wait之间必须有严格的happens before关系
(1) 对于整个代码块中所创建的全部Add操作,可被严格分割为不交的两个组别A和B,若设置A happens before B
(2) 存在一个Wait操作 W,使得A happens before B
(3) 并且该 W happens before B
Sync.Pool 缓存池
大量重复地创建许多对象,GC工作量飙升,CPU频繁掉底,产生CPU毛刺。这时可以用sync.Pool来缓存对象,减轻对GC的消耗
调用Get方法时,如果池子Pool缓存了对象,就直接返回缓存的对象,如果没有,就New函数创建一个新的对象
Get方法取出来的对象和上次Put进去的对象实际上是同一个,Pool没有做任何“清空”的处理,所以需要在Put之前,把对象清空
gin框架,对context的取用,也使用了sync.Pool
go vet工具可以检测到用户代码是否复制了Pool,是go1.7引入的一个静态检查机制,不仅仅工作在运行时或者标准库,同时也对用户代码有效
PoolDeque 是一个队列的接口,poolDequeue是一个具体的实现者,实现为单生产者,多消费者的固定大小的无锁Ring 式队列,生产者可以从head插入,head删除,而消费者仅可以从tail删除
关键函数
Pool.pin() 将当前goroutine和P绑定在一起,禁止抢占,并且返回对应的poolLocal以及p的id
popHead() 会从头删掉,并且返回queue的头结点,queue为空,返回false
getSlow() 如果在shared里没有获取到缓存对象,则继续调用Pool.getSlow(),尝试从其他P的poolLocal偷取
popTail()从尾部移除一个元素
victim
victim在poolCleanup的时候被赋值,而poolCLeanup在GC的时候被调用
先把victim和victimsize情空,再把local和localsize的数据全放过来 ;下一次GC来临之前,如果有Get调用则会从p.victim取,获取后也不放回victim,这样在一定程度上也减小了下一次GC的开销,原来1次GC的开销拉长到2次,减小了GC的抖动