美文网首页
golang的sync.Pool的使用

golang的sync.Pool的使用

作者: 个00个 | 来源:发表于2019-03-07 20:57 被阅读0次

    可以看这篇文章
    https://blog.csdn.net/yongjian_lian/article/details/42058893

    这个玩意的出现是为了解决 gc 的问题, 核心点在于 重用对象, 提高性能. 减少内存的分配.

    下面看个例子

    package main
    
    import (
        "sync"
        "fmt"
    )
    
    func main() {
        p := &sync.Pool{
            New: func() interface{} {
                return 0
            },
        }
    
        a := p.Get().(int)
        fmt.Println(a)
        p.Put(1)
        p.Put(4)
        p.Put(2)
        p.Put(5)
    
        b := p.Get().(int)
        // runtime.GC()  // 执行回收操作后 1 0 0 0
        c := p.Get().(int)
        d := p.Get().(int)
        fmt.Println(b, c, d, p.Get())
    }
    
    

    输出

    0
    1 5 2 4   // 神奇的输出
    

    总结一下文章里面说的

    1. 缓存对象没有数量限制 即只受制于物理限制 - 内存
    2. 缓存对象的过期  注册了  runtime_registerPoolCleanup(poolCleanup) 函数,  每次gc之前都会调用.
    sync.Pool的缓存的期限只是在两次gc之间...  因此不能实现socket连接池.
    

    这真是一个有意思的小程序. = - =. 研究了好久才明白的 . 无私分享一下...

    package main
    
    import (
        "sync"
        "fmt"
        "runtime"
        "time"
    )
    
    func main() {
        p := &sync.Pool{
            New: func() interface{} {
                return 0
            },
        }
    
        runtime.GOMAXPROCS(2)
    
        a := p.Get().(int)
        fmt.Println(a)
        p.Put(1)
    
        wg := sync.WaitGroup{}
        wg.Add(1)
        go func(){
            defer wg.Done()
            p.Put(100)
        }()
        wg.Wait()
    
        time.Sleep(time.Second * 1)
    
        p.Put(4)
        p.Put(5)
    
        fmt.Println(p.Get())
        fmt.Println(p.Get())
        fmt.Println(p.Get())
            // fmt.Println(p.Get())
    }
    
    

    有趣的输出结果

    1:  0  1  5  4 
    2:  0  100  5  4
    3:  0   4  5  100
    

    是不是很有趣. 这里解释一下. 首先我们要搞清楚的一些概念

    1. 这个sync.Pool的缓存是每一个 P 有一个私有对象, 然后有一个共享列表对象.
    2. 每次Get的时候优先取自己 P的私有对象, 然后取自己P的共享列表对象, 且取共享的时候是 先进后出的栈. 最后取别的P的共享列表对象, 但是取不到别人的私有对象...
    3. time.Sleep 可能会让goroutine 切换 P执行
    4. 这里程序注册了2个P
    1: 0 1 5 4    // P1私有设置了 1 , 然后 goroutine在第二个上执行, P2私有设置了 100, 然后 4, 5 分别被塞到了 P1的共享变量里... 也就意味着最后的Get是在P1 执行的. 所以先取私有  1 ,  然后共享先进后出 5  4 
    // P1 私->1  P1 公 -> 100, 4, 5  => 100没取出来.
    
    2: 0 100 5 4 // P1 私 -> 1,  P2 私 -> 100 ,  P2 公 -> 4 , 5 最后在P2上执行.
    
    3: 0 4 5 100  //  P1 私 -> 1,  P1公 -> 100 ,  P2 私 -> 4  P2 公 -> 5  最后在P2上执行.    4 . 5 . 100 
    

    有趣吧~ 这个pool的对象是跟P绑定的~ goroutine 走掉了 但是他留下了 put的私有变量 ~~~
    可以把上面最后一行的 打印打开. ~ 大家可以试下结果 . 每种结果出现的概率不一样. 需要多跑几次.

    测试时go1.11版本

    +++ 备注
    gc会回收pool里的东西 , 这个pool只是增加了对象重用的机会~~~

    相关文章

      网友评论

          本文标题:golang的sync.Pool的使用

          本文链接:https://www.haomeiwen.com/subject/eplhpqtx.html