首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Go 并发实战 -- sync Pool

前言

sync包中最后一个要说的API是sync.Pool,本质上来说Pool应该不算是sync并发相关的内容,但是既然放在sync里了,并且在并发场景下共用一些对象其实还挺常见的,就一起说一下吧。 Pool目的是对象的共用,解决的是减少内存的占用及GC频发带来的性能损耗,对于一些大对象,或者构造代价高的对象还是很有必要通过pool来缓存的。

语法基础

Pool的API非常简单:

image.png

通常来说一个pool存放一个type或者一个interface的对象。 Get函数用于取对象(取的顺序随机) Push函数用于添加对象 假设现在池子是空的Push一个对象,然后Get取出来的就是这个对象,如果再执行get取到的就是nil了,所以我们用完之后记得push进去,来保证后续还能继续使用。 Pool的大小是不做限制的,仅与内存限制有关,如果想做一个有尺寸的池子,在上层封装一下就好了。 来看个demo:

代码语言:javascript
复制
func main() {
    pool := sync.Pool{}
    pool.Put("1")
    pool.Put("2")
    pool.Put("3")
    pool.Put("4")
    pool.Put("5")
    fmt.Println(pool.Get())
    fmt.Println(pool.Get())
    fmt.Println(pool.Get())
    fmt.Println(pool.Get())
    fmt.Println(pool.Get())
    fmt.Println(pool.Get())
}

输出:

image.png

其实我们可以配合Cond 完成一个经典的使用:

代码语言:javascript
复制
func main() {
    lock := &sync.Mutex{}
    cond := sync.NewCond(lock)
    pool := &sync.Pool{}
    produce(cond, pool)
    for i:=0; i<12; i++ {
        consume(cond, pool, i)
    }
    time.Sleep(102*time.Second)
}
func consume(cond *sync.Cond, pool *sync.Pool, i int) {
    go func() {
        for true {
            cond.L.Lock()
            v := pool.Get()
            for ; v == nil; v= pool.Get() {
                cond.Wait()
            }
            if v != nil {
                fmt.Println("consumer "+strconv.Itoa(i)+" consume: ", v)
            }
            cond.L.Unlock()
            pool.Put(v)
            cond.Broadcast()
            time.Sleep(1*time.Second)
        }
    }()
}
func produce(cond *sync.Cond, pool *sync.Pool) {
    go func() {
        for i:=0; i<6; i++ {
            time.Sleep(1*time.Second)
            fmt.Println("produce: ", i)
            pool.Put(i)
            cond.Broadcast()
        }
    }()
}

输出:

image.png

看完这个demo,应该就对于pool及cond的使用就更加清晰了 关于Pool的实现大家看看源码就可以了,注释写的非常详细,就不过多赘述了:src/sync/pool.go 关于sync.Pool暂时就先介绍这么多。

下一篇
举报
领券