天天看点

go随聊-临时对象池sync.Pool

sync.Pool

        一个sync.Pool对象就是一组临时对象的集合。Pool是协程安全的。Pool用于存储那些被分配了但是没有被使用,而未来可能会使用的值,以减小垃圾回收的压力。我们可以把sync.Pool类型值看作是存放可被重复使用的值的容器。此类容器是自动伸缩的、高效的,同时也是并发安全的。

Pool定义

type Pool struct {
    func (p *Pool) Get() interface{} 
    func (p *Pool) Put(x interface{}) 
    New func() interface{}
}
           

sync.Pool 最常用的两个函数Get/Put,对象池在Get的时候如果里面没有对象会返回nil,所以我们需要New function来确保当对象池为空时,重新生成一个对象返回,前者的功能是从池中获取一个interface{}类型的值,而后者的作用则是把一个interface{}类型的值放置于池中。

Get/Put

var BufferPool = sync.Pool{
	New: func() interface{} { return helper.UUIDBuild() },
}
func TestNewHttpWrap(t *testing.T) {
	for {
		tmp:=BufferPool.Get()
		fmt.Println(tmp)
		time.Sleep(time.Second)
	}
}
--------------------------------------------------------------------
3ef869eb18534a7888e8295cdb97f24e
0503331e7361433eb16d4dc87942b770
c24d2e269bb94d798fbf11da6b1d2468
2ec763ee841a4571a204c2b9663279c1
7c34f977fa204a6ea15422e971756cf7
72a27faaea8147e9ab29389fe65cc3df
           

每次都调用Get取对象,但是不调用Put,则每次取的值都是新创建的

var BufferPool = sync.Pool{
	New: func() interface{} { return helper.UUIDBuild() },
}
func TestNewHttpWrap(t *testing.T) {
	for i:=0;;i++ {
		tmp:=BufferPool.Get()
		fmt.Println(tmp)
		BufferPool.Put(tmp)
		time.Sleep(time.Second)
	}
}
----------------------------------------------------------------
e1ea52bd1a204f55889330d44d97de49
22c2a6f9d4784457a753ab5eccdb7bd7
e1ea52bd1a204f55889330d44d97de49
22c2a6f9d4784457a753ab5eccdb7bd7
e1ea52bd1a204f55889330d44d97de49
           

每次都调用Get取对象,用完后Put,则每次取的值就会是之前存在的,这样就减少了创建新对象的操作

临时的概念

        对象池使用是较简单的,但原生的sync.Pool有个较大的问题:我们不能自由控制Pool中元素的数量,放进Pool中的对象每次GC发生时都会被清理掉。这使得sync.Pool做简单的对象池还可以,但做连接池就有点心有余而力不足了,比如:在高并发的情景下一旦Pool中的连接被GC清理掉,那每次连接DB都需要重新三次握手建立连接,这个代价就较大了。

例子:

var BufferPool = sync.Pool{
	New: func() interface{} { return helper.UUIDBuild() },
}
func TestNewHttpWrap(t *testing.T) {
	for i:=0;;i++ {
		tmp:=BufferPool.Get()
		fmt.Println(tmp)
		BufferPool.Put(tmp)
		time.Sleep(time.Second)
		//每10秒GC一次
		if (i%10)==0 {
			runtime.GC()
			fmt.Println("GC")
		}
	}
}
---------------------------------------------------------
812a05e41b6748d09aad4ef2003b581e
06e9611162324089b9b08ada47d109e4
812a05e41b6748d09aad4ef2003b581e
06e9611162324089b9b08ada47d109e4
812a05e41b6748d09aad4ef2003b581e
GC
39dc10511e4043ff8b3ea9ed47464067  //GC之后812a05e41b6748d09aad4ef2003b581e已经不存在了
d4e34df336ea44479022f4b138b0a448
39dc10511e4043ff8b3ea9ed47464067
d4e34df336ea44479022f4b138b0a448
39dc10511e4043ff8b3ea9ed47464067
           

可以看到GC之前Pool中Get到的对象是之前创建的,一旦GC之后,Pool中对象全部清空了,Get时又重新创建了。

go随聊-临时对象池sync.Pool