设为首页 收藏本站
查看: 958|回复: 0

[经验分享] Golang 临时对象池 sync.Pool

[复制链接]

尚未签到

发表于 2018-9-20 09:40:18 | 显示全部楼层 |阅读模式
  Go 1.3 的sync包中加入一个新特性:Pool。官方文档可以看这里http://golang.org/pkg/sync/#Pool
  这个类设计的目的是用来保存和复用临时对象,以减少内存分配,降低CG压力。
  

type Pool  func (p *Pool) Get() interface{}
  func (p *Pool) Put(x interface{})
  New func() interface{}
  

  

  下面说说Pool的实现:
  1.定时清理
  文档上说,保存在Pool中的对象会在没有任何通知的情况下被自动移除掉。实际上,这个清理过程是在每次垃圾回收之前做的。垃圾回收是固定两分钟触发一次。而且每次清理会将Pool中的所有对象都清理掉!
  2.如何管理数据
  先看看两个数据结构
  

type Pool struct {  local     unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal

  localSize uintptr        //>  // 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() interface{}
  
}
  
// Local per-P Pool appendix.
  
type poolLocal struct {
  private interface{}   // Can be used only by the respective P.
  shared  []interface{} // Can be used by any P.
  Mutex                 // Protects shared.
  pad     [128]byte     // Prevents false sharing.
  
}
  

  

  Pool是提供给外部使用的对象。其中的local成员的真实类型是一个poolLocal数组,localSize是数组长度。poolLocal是真正保存数据的地方。priveate保存了一个临时对象,shared是保存临时对象的数组。
  为什么Pool中需要这么多poolLocal对象呢?实际上,Pool是给每个线程分配了一个poolLocal对象。也就是说local数组的长度,就是工作线程的数量(size := runtime.GOMAXPROCS(0))。当多线程在并发读写的时候,通常情况下都是在自己线程的poolLocal中存取数据。当自己线程的poolLocal中没有数据时,才会尝试加锁去其他线程的poolLocal中“偷”数据。
  

func (p *Pool) Get() interface{} {  if raceenabled {
  if p.New != nil {
  return p.New()
  }
  return nil
  }
  l := p.pin()  // 获取当前线程的poolLocal对象,也就是p.local[pid]。
  x := l.private
  l.private = nil
  runtime_procUnpin()
  if x != nil {
  return x
  }
  l.Lock()
  last := len(l.shared) - 1
  if last >= 0 {
  x = l.shared[last]
  l.shared = l.shared[:last]
  }
  l.Unlock()
  if x != nil {
  return x
  }
  return p.getSlow()
  
}
  

  

  Pool.Get的时候,首先会在local数组中获取当前线程对应的poolLocal对象。如果private中有数据,则取出来直接返回。如果没有则先锁住shared,有数据则直接返回。
  为什么这里要锁住。答案在getSlow中。因为当shared中没有数据的时候,会尝试去其他的poolLocal的shared中偷数据。
  Go语言的goroutine虽然可以创建很多,但是真正能物理上并发运行的goroutine数量是有限的,是由runtime.GOMAXPROCS(0)设置的。所以这个Pool高效的设计的地方就在于将数据分散在了各个真正并发的线程中,每个线程优先从自己的poolLocal中获取数据,很大程度上降低了锁竞争。  



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-598673-1-1.html 上篇帖子: 借助VSCode搭建Golang开发环境 下篇帖子: golang环境中grpc与zipkin的集成
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表