例如tcp连接、数据库连接这类耗时的操作,可以放在池中,避免每次使用时都重新创建。 池化的对象可能会被垃圾回收,对于数据库的长链接是不合适的。 因此有专门用于TCP连接池、数据库连接池,还会有一种常见的Woker Pool。
注意点: (1) sync.Pool本身线程安全,多个goroutine可以并发调用其存取方法 (2) sync.Pool不可在使用之后再复制使用
sync.Pool用于保存一组可独立访问的临时对象,注意加粗的临时,说明它池化的对象在未来某个时候会被 毫无征兆的移除掉。
三个方法: New() interface{} 用于Get无对象时创建,否则返回nil Get() 用于取对象 Put() 用于存对象
- 在使用Pool存储byte slice这类buffer时,注意slice的cap如果过大,就不要回收。
- 如果Pool中的buffer容量大,但是只需要小容量的buffer,则可以根据容量分级,创建多个Pool
除了分层节省空间的buffer池,还有其他的第三方库:
- bytebufferpool
- oxtoacart/bpool
连接池
Pool 的另一个很常用的一个场景就是保持 TCP 的连接。 (事实上,很少用sync.Pool去池化连接对象,因为sync.Pool会无通知的将某个连接回收,因此 会其他方法来池化对象)
- 标准库中的 http client 池
http.Client 实现连接池的代码是在 Transport 类型中,它使用 idleConn 保存持久化的可重用的长连接: - fatih/pool的tcp连接池
它的 Pool 是通过 Channel 实现的,空闲的连接放入到 Channel 中,这也是 Channel 的一个应用场景: - 数据库连接池
通过 MaxOpenConns 和 MaxIdleConns 控制最大的连接数和最大的 idle 的连接数。 - Memcached Client 连接池
gomemcache是他使用 Go 开发的 Memchaced 的客户端,其中也用了连接池的方式池化 Memcached 的连接
Worker Pool
goroutine并不是越多越好,我们会创建一个Worker Pool来减少goroutine的使用。
总结
Pool是一个通用的概念,当程序中有很多需要重复创建的对象,可以创建池类对象。
|