文档章节

golang sync.Pool 使用和源码分析

鼎铭
 鼎铭
发布于 06/12 10:26
字数 883
阅读 356
收藏 5
点赞 0
评论 0

    golang 在写高频服务的时候,如何解决gc问题,对象池是一个很有效果的方式,本文阐述下对象池的两种使用方式,和对对象池的源码分析,以及使用pool 的要点。golang 的对象池源码在避免锁竞争还利用了分段锁的思想减少锁的竞争,代码比较精彩。

该文章后续仍在不断的更新修改中, 请移步到原文地址http://www.dmwan.cc/?p=152

    首先sync.Pool 有两种使用方式,使用效果没有区别。

    第一种,实例化的时候,实现New 函数即可:

package main  
 
import(  
    "fmt"  
    "sync"  
)  
 
func main() {  
    p := &sync.Pool{  
        New: func() interface{} {  
            return 0  
        },  
    }  
 
    a := p.Get().(int)  
    p.Put(1)  
    b := p.Get().(int)  
    fmt.Println(a, b)  
}  

        第二种,get 取值的时候,判断是否为nil 即可。

package main  
 
import(  
    "fmt"  
    "sync"  
)  
 
func main() {  
    p := &sync.Pool{}  
    a := p.Get()
    if a == nil {
       a = func() interface{} {  
            return 0  
        }
    }
    p.Put(1)  
    b := p.Get().(int)  
    fmt.Println(a, b)  
}  

    这两种实现方式,最后的效果是一样的,也反应了pool 的特性,get 返回值是new 的对象,或者nil。

    然后,pool 底层到底是怎样的数据结构?就是一个metux 和 slice?其实也是类似,只是加了些其他特性而已,下面数据结构:

type Pool struct {  
    local     unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal  
    localSize uintptr        // size of the local array  
  
    // 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.  
}  

    这里的local 是个poolLocal 的数组,localsize 是数组的大小。其中,从get 和put 方法看,为每个thread 维护了一个poolLocal 数据结构。不同线程取数据的时候,先判断下hash 到哪个线程去了,分别去对应的poolLocal 中去取数据,这是利用了分段锁的思想。

    具体实现可以看get 方法:

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()  //当本线程的缓存对象已经没有,去其他线程缓存列表中取
}  

    这里代码的注释比较详尽了,本来维护一个mutex ,现在变成竞争多个mutex ,降低了锁的竞争。性能自然非常好。

    最后是getSlow 方法,从其他线程的变量中去steal 偷。runtime 也喜欢搞这种事。。。

func (p *Pool) getSlow() (x interface{}) {  
    // See the comment in pin regarding ordering of the loads.  
    size := atomic.LoadUintptr(&p.localSize) // load-acquire  
    local := p.local                         // load-consume  
    // Try to steal one element from other procs.  
    pid := runtime_procPin()  
    runtime_procUnpin()  
    for i := 0; i < int(size); i++ {  //遍历其他线程的缓存队列
        l := indexLocal(local, (pid+i+1)%int(size))  
        l.Lock()  
        last := len(l.shared) - 1  
        if last >= 0 {  
            x = l.shared[last]  
            l.shared = l.shared[:last]  
            l.Unlock()  
            break  
        }  
        l.Unlock()  
    }  
  
    if x == nil && p.New != nil {  //其他线程没有,那么new 一个
        x = p.New()  
    }  
    return x  
}  

    最后,pool 还有个特性是当gc 的时候所有的缓存对象都要被清理,调用的是PoolCleanUp,没什么特别之处。但是这个特性要求了pool 绝对不能做有状态的缓存,类似socket的缓存池。

    这里的分段锁,为每个线程bind 一个队列,还考虑到了均衡的情况,是比较巧妙和值得学习的。以上。。。

© 著作权归作者所有

共有 人打赏支持
鼎铭
粉丝 17
博文 63
码字总数 36701
作品 0
东城
程序员
同步之sync.Pool临时对象池

同步之sync.Pool临时对象池 当多个goroutine都需要创建同一个对象的时候,如果goroutine过多,可能导致对象的创建数目剧增。 而对象又是占用内存的,进而导致的就是内存回收的GC压力徒增。造...

秋风醉了 ⋅ 2016/08/05 ⋅ 0

golang sync.Pool试用说明及注意事项

Go tip 是 Go 语言的实验分支,包含了很多尚在讨论,但很有可能会加入 stable 分支的特性。“Go tip 在做什么”(原文地址:What's happening in Go tip)分析总结了 Go 语言尚在开发中的一些...

wkh ⋅ 2014/06/20 ⋅ 0

[转载]golang sync.Pool

Go 1.3 的sync包中加入一个新特性:Pool。 官方文档可以看这里http://golang.org/pkg/sync/#Pool 这个类设计的目的是用来保存和复用临时对象,以减少内存分配,降低CG压力。 Get返回Pool中的...

大蓝妹 ⋅ 2014/10/29 ⋅ 0

Golang profiling and optimizing

本文总结自Profiling and Optimizing Go,对应的PPT,有梯子的可以直接看视频,没梯子的也可以看下这篇文章:) 。 Golang的runtime内建了强大的分析工具pprof,能帮助我们对程序运行时的CPU、...

Rokety Yang ⋅ 01/27 ⋅ 0

Docker自发现注册服务regd研发

前言 [技术源于艺术, 艺术源于生活] 1) 这是我第一次发布程序相关的技术文章, 10年前发表过很多关于3dsmax和maya的技术文章 2) 有人无端转载我的文章, 所以这里留一个我的联系方式, 欢迎讨论...

funwun ⋅ 2016/05/16 ⋅ 2

好文收藏系列(二)

分析redis性能的项目 https://github.com/Instagram/redis-faina DB性能分析思路之全量query分析 http://txyey.org/?p=60 如何创建自适应系统来增强用户体验 http://www.alibuybuy.com/posts...

王二狗子11 ⋅ 01/07 ⋅ 0

golang 核心开发者 Dmitry Vyukov(1.1 调度器作者) 关于性能剖析

让我们假设你有一golang 程序,想改善其性能。有几种工具可以帮我们完成这个任务。这些工具可以帮我们识别程序中的热点(cpu,io,memory), 热点即是那些需要我们集中精力于其上,能显著改善改善...

yujian0231 ⋅ 2015/01/26 ⋅ 1

goalng 工具包安装

golang工具包的安装 以 安装godoc 为例: 1. godoc 源码下载 git clone https://github.com/golang/tools golang.org/x/tools 即在 GOPATH 下构建一个 golang.org/x/tools 的包. note: 如果从......

SLonger ⋅ 2016/04/28 ⋅ 0

golang1.5源码安装说明

golang 1.5的安装说明 由于golang1.5使用了golang来编译自己,所以需要先安装golang1.4,然后使用1.4的go来编译go1.5的源码 源码包官方的下载地址 https://go.googlesource.com/go https://g...

leicc ⋅ 2015/10/17 ⋅ 0

memcache 源码分析之开场白

装逼以前的一段独白: 现在2018年5月5号。距离上次写技术博客还是2016好像是12月份的事情,当时离职在陪老婆考试,我算是半给陪考和半个鼓励师。呵呵。。不知不觉时间到了2018年,我也来到了...

佛观一杯水 ⋅ 05/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Linux中的端口大全

1 被LANA定义的端口 端口 名称 描述 1 tcpmux TCP 端口服务多路复用 5 rje 远程作业入口 7 echo Echo 服务 9 discard 用于连接测试的空服务 11 systat 用于列举连接了的端口的系统状态 13 d...

寰宇01 ⋅ 16分钟前 ⋅ 0

Confluence 6 如何备份存储文件和页面信息

备份的 ZIP 文件包含有 entities.xml,这个 XML 文件包含有 Confluence 的所有页面内容和存储附件的目录。 备份 Zip 文件结构 页面的附件是存储在附件存储目录中的,通过页面和附件 ID 进行识...

honeymose ⋅ 18分钟前 ⋅ 0

【每天一个JQuery特效】根据状态确定是否滑入或滑出被选元素

主要效果: 本文主要采用slideToggle()方法实现以一行代码同时实现以展开或收缩的方式显示或隐藏被选元素。 主要代码如下: <!DOCTYPE html><html><head><meta charset="UTF-8">...

Rhymo-Wu ⋅ 22分钟前 ⋅ 0

度量.net framework 迁移到.net core的工作量

把现有的.net framework程序迁移到.net core上,是一个非常复杂的工作,特别是一些API在两个平台上还不能同时支持。两个类库的差异性,通过人工很难识别全。好在微软的工程师们考虑到了我们顾...

李朝强 ⋅ 28分钟前 ⋅ 0

请不要在“微服务”的狂热中迷失自我!

微服务在过去几年一直是一个非常热门的话题(附录1)。何为“微服务的疯狂”,举个例子: 众所周知,Netflix在DevOps上的表现非常棒。Netfix可以做微服务。因此:如果我做微服务,我也将非常...

harries ⋅ 29分钟前 ⋅ 0

oAuth2 升级Spring Cloud Finchley.RELEASE踩坑分享

背景 6.19号,spring团队发布了期待已久的 Spring Cloud Finchley.RELEASE 版本。 重要变化: 基于Spring Boot 2.0.X 不兼容 Spring Boot 1.5.X 期间踩过几个坑,分享出来给大伙,主要是关于...

冷冷gg ⋅ 59分钟前 ⋅ 0

OSChina 周一乱弹 —— 理发师小姐姐的魔法

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @冰冰棒- :分享田馥甄的单曲《My Love》 《My Love》- 田馥甄 手机党少年们想听歌,请使劲儿戳(这里) @Li-Wang :哎,头发又长了。。。又要...

小小编辑 ⋅ 今天 ⋅ 8

Kafka1.0.X_消费者API详解2

偏移量由消费者管理 kafka Consumer Api还提供了自己存储offset的功能,将offset和data做到原子性,可以让消费具有Exactly Once 的语义,比kafka默认的At-least Once更强大 消费者从指定分区...

特拉仔 ⋅ 今天 ⋅ 0

NEO智能合约之发布和升级(二)

接NEO智能合约之发布和升级(一),我们接下来说说智能合约的升级功能。 一 准备工作 合约的升级需要在合约内预先设置好升级接口,以方便在升级时调用。接下来我们对NEO智能合约之发布和升级...

红烧飞鱼 ⋅ 今天 ⋅ 0

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部