内容简介:Go版本1.13.1Go中有sync.Pool类型,我们可以把它理解成存放临时值的容器,之所以加上“临时”两个字,是因为它会在GC过程的STW步骤被清理。sync.Pool类型使用前可以给它的New字段赋值,New字段类型是func() interface{},一个函数类型,该函数一般在池内为空的时候才会调用
Go版本1.13.1
Go中有sync.Pool类型,我们可以把它理解成存放临时值的容器,之所以加上“临时”两个字,是因为它会在GC过程的STW步骤被清理。
sync.Pool类型使用前可以给它的New字段赋值,New字段类型是func() interface{},一个函数类型,该函数一般在池内为空的时候才会调用
sync.Pool有两个公开的方法,一个Put,一个Get,作用看函数名就知道了
Go的并发模型是GMP模型,sync.Pool给每个P都建立了本地池,一个本地私有池,一个本地共享池,执行Get方法时,先从本地私有池取,取不到,去本地共享池,再取不到,去其他P的共享池中取,失败的话去victim cache中取,再失败就调用New方法,New生成的对象不会放到本地池中,是直接返回给调用方的。
我今天在书上发现一个“坑”,其实是 go 版本的问题导致的,书中的例子大概是这样的
package main import ( "fmt" "runtime" "runtime/debug" "sync" "sync/atomic" ) var ( count int32 initFunc = func() interface{} { return atomic.AddInt32(&count, 1) } pool = sync.Pool{New:initFunc} ) func main() { debug.SetGCPercent(debug.SetGCPercent(-1)) v1 := pool.Get() fmt.Printf("value 1: %v\n", v1) pool.Put(10) pool.Put(11) pool.Put(12) v2 := pool.Get() fmt.Printf("value 2: %v\n", v2) runtime.GC() v3 := pool.Get() fmt.Printf("value 3: %v\n", v3) pool.New = nil v4 := pool.Get() fmt.Printf("value 4: %v\n", v4) } // 书中的输出结果 value 1: 1 value 2: 10 value 3: 2 value 4: <nil> // 我实际的输出结果 value 1: 1 value 2: 10 value 3: 11 value 4: 12
例子里是想展示GC时会清空Pool里面的元素,清空后会调用New方法
我实际执行发现结果和书上的不一样,我当时在想怎么会出现这种情况,难道GC有问题?后来经过翻看源码,查看GC日志,发现一个关键的代码段,sync.Pool在STW时会执行poolCleanup函数
func poolCleanup() { // Drop victim caches from all pools. for _, p := range oldPools { p.victim = nil p.victimSize = 0 } // Move primary cache to victim cache. for _, p := range allPools { p.victim = p.local p.victimSize = p.localSize p.local = nil p.localSize = 0 } oldPools, allPools = allPools, nil }
问题就出现在上面这个函数中,我这个版本的go,sync.Pool在GC时,数据会转到victim里面,也就是说会幸存一次GC,所以要实现书中的效果,需要两次GC。
后面去查看go代码提交日志,确实发现了这个代码的 提交记录
总结
总结一下sync.Pool的两个特性
- 对垃圾回收友好
- 可以把对象值产生的存储压力进行分摊
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 图解词法作用域与作用域链
- javascript作用域之块级作用域
- javascript静态作用域和动态作用域
- JavaScript系列之作用域和作用域链
- 【7】JavaScript 函数高级——作用域与作用域链
- 深入学习js之——词法作用域和动态作用域
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++设计新思维
(美)Andrei Alexandrescu / 侯捷、於春景 / 华中科技大学出版社 / 2003-03 / 59.8
本书从根本上展示了generic patterns(泛型模式)或pattern templates(模式模板),并将它们视之为“在C++中创造可扩充设计”的一种功能强大的新方法。这种方法结合了template和patterns,你可能未曾想过,但的确存在。为C++打开了全新视野,而且不仅仅在编程方面,还在于软件设计本身;对软件分析和软件体系结构来说,它也具有丰富的内涵。一起来看看 《C++设计新思维》 这本书的介绍吧!