天天看點

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