说清楚了sync.pool的文章
来源:互联网 发布:js 格式化数字 前补零 编辑:程序博客网 时间:2024/04/25 21:15
转载自 https://studygolang.com/articles/3506
先来看看如何使用一个pool:
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)
}
上面创建了一个缓存int对象的一个pool,先从池获取一个对象然后放进去一个对象再取出一个对象,程序的输出是0 1。创建的时候可以指定一个New函数,获取对象的时候如何在池里面找不到缓存的对象将会使用指定的new函数创建一个返回,如果没有new函数则返回nil。用法是不是很简单,我们这里就不多说,下面来说说我们关心的问题:
1、缓存对象的数量和期限
上面我们可以看到pool创建的时候是不能指定大小的,所有sync.Pool的缓存对象数量是没有限制的(只受限于内存),因此使用sync.pool是没办法做到控制缓存对象数量的个数的。另外sync.pool缓存对象的期限是很诡异的,先看一下src/pkg/sync/pool.go里面的一段实现代码:
func init() {
runtime_registerPoolCleanup(poolCleanup)
}
可以看到pool包在init的时候注册了一个poolCleanup函数,它会清除所有的pool里面的所有缓存的对象,该函数注册进去之后会在每次gc之前都会调用,因此sync.Pool缓存的期限只是两次gc之间这段时间。例如我们把上面的例子改成下面这样之后,输出的结果将是0 0。正因gc的时候会清掉缓存对象,也不用担心pool会无限增大的问题。
a := p.Get().(int)p.Put(1)runtime.GC()b := p.Get().(int)fmt.Println(a, b)
这是很多人错误理解的地方,正因为这样,我们是不可以使用sync.Pool去实现一个socket连接池的。
2、缓存对象的开销
如何在多个goroutine之间使用同一个pool做到高效呢?官方的做法就是尽量减少竞争,因为sync.pool为每个P(当执行一个pool的get或者put操作的时候都会先把当前的goroutine固定到某个P的子池上面,然后再对该子池进行操作。每个子池里面有一个私有对象和共享列表对象,私有对象是只有对应的P能够访问,因为一个P同一时间只能执行一个goroutine,因此对私有对象存取操作是不需要加锁的。共享列表是和其他P分享的,因此操作共享列表是需要加锁的。
获取对象过程是:
1)固定到某个P,尝试从私有对象获取,如果私有对象非空则返回该对象,并把私有对象置空;
2)如果私有对象是空的时候,就去当前子池的共享列表获取(需要加锁);
3)如果当前子池的共享列表也是空的,那么就尝试去其他P的子池的共享列表偷取一个(需要加锁);
4)如果其他子池都是空的,最后就用用户指定的New函数产生一个新的对象返回。
可以看到一次get操作最少0次加锁,最大N(N等于MAXPROCS)次加锁。
归还对象的过程:
1)固定到某个P,如果私有对象为空则放到私有对象;
2)否则加入到该P子池的共享列表中(需要加锁)。
可以看到一次put操作最少0次加锁,最多1次加锁。
由于goroutine具体会分配到那个P执行是golang的协程调度系统决定的,因此在MAXPROCS>1的情况下,多goroutine用同一个sync.Pool的话,各个P的子池之间缓存的对象是否平衡以及开销如何是没办法准确衡量的。但如果goroutine数目和缓存的对象数目远远大于MAXPROCS的话,概率上说应该是相对平衡的。
总的来说,sync.Pool的定位不是做类似连接池的东西,它的用途仅仅是增加对象重用的几率,减少gc的负担,而开销方面也不是很便宜的。
- 说清楚了sync.pool的文章
- golang的临时对象池sync.Pool
- go的临时对象池--sync.Pool
- SLAM的前世今生 终于有人说清楚了
- SLAM的前世今生 终于有人说清楚了
- SLAM的前世今生 终于有人说清楚了
- SLAM的前世今生 终于有人说清楚了
- 终于有人把股市集合竞价的秘密说清楚了
- golang有用的库及工具 之 sync.Pool改造
- SQL优化:一篇文章说清楚Oracle Hint的正确使用姿势
- SQL优化:一篇文章说清楚Oracle Hint的正确使用姿势
- SQL优化:一篇文章说清楚Oracle Hint的正确使用姿势
- MUI多端发布开发指南(终于把MUI的使用场景说清楚了)
- SLAM的前世今生 终于有人说清楚了 | 硬创公开课
- SLAM的前世今生 终于有人说清楚了 | 硬创公开课
- SLAM的前世今生 终于有人说清楚了 | 硬创公开课
- SLAM的前世今生 终于有人说清楚了 | 硬创公开课
- 写论文,为什么要写参考文献?感觉完全不必要,把自己的研究成果说清楚不就行了?
- [App] rhel7 下安装 Heartbeat 3.0.6
- jdbc连接hive的问题
- ubuntu16.04 安装tensorflow
- Android studio请求网络数据ListView异步加载展示文字条目 ImageLoadler加载图片
- Spring Bean详解
- 说清楚了sync.pool的文章
- Android OOM
- C语言的基本输入与输出函数(全解)
- java中如何理解继承和接口的实际用途
- 分词资料
- python:浅析python中__name__ = "__main__"的作用
- Python数据挖掘建模 chapter_5 神经网络算法
- Apache Shiro 快速入门教程,shiro 基础教程
- FreeBSD下的开机自启动