今天要進到比較理論的章節,也是比較難解說的部分,如果有什麼疑問或寫錯的地方,歡迎留言指教我。
在這邊大家一定會有疑問? 什麼是 buffer pool ,它有下面優點
已使用情境來說,我覺得類似聊天室的應用,需要大量高頻的接收 message ,其實就很適合使用 buffer pool ,畢竟你總不可能有 client 送一個 message 進來 server,就重劃一個記憶體空間給它,處理完就把那塊空間 gc 掉,這樣其實是很吃 CPU 資源的。
下面是一個沒有使用 buffer pool的一個 socket 應用流程圖
如果改成使用 buufer pool 會大概像下面這樣,由圖可以看到,socket client,不像上圖一樣,只要有訊息進來就自己 new 4kb 的空間,改由另一個 buffer pool 去控制,所以當 socket client 需要用時,則向此 buffer pool 取 4kb,用完的時侯,再把 4kb 還回來,反覆利用,避免不斷造成 garbage collector (GC) 問題。
下面用一個簡單的範例來說明如何實作
type BufferPool struct {
c chan *bytes.Buffer
}
//預劃 buffer pool 空間
func NewBufferPool(size int) (bp *BufferPool) {
return &SizedBufferPool{
c: make(chan *bytes.Buffer, size),
}
}
//這邊是拿取一個新的 buffer
func (bp *BufferPool) Get() (b *bytes.Buffer) {
select {
case b = <-bp.c:
//看看 buffer pool 如果有空閑的 buffer 則使用已經建構過的 buffer
default:
//如果當下沒有空閑的 buffer 則重新建構一個出來
b = bytes.NewBuffer(make([]byte, 0, bp.a))
}
return
}
//把用完的 buffer 放回 pool 裡面
func (bp *BufferPool) Put(b *bytes.Buffer) {
b.Reset()
// 看 buffer pool 空間是否已滿,如果已滿則丟棄掉此 buffer
select {
case bp.c <- b:
default: //放不進去 buffer pool 代表 已滿,則丟掉此 buffer
}
}
上面範例可以看到,這是運用到 golang select & channel 的特性,把 channel 當作 buffer pool,用 select 當作控制 buufer pool 的閘道。