下面由golang教程欄目給大家介紹Golang連接池的幾種實(shí)現(xiàn)案例,希望對需要的朋友有所幫助!
因?yàn)門CP的三次握手等等原因,建立一個(gè)連接是一件成本比較高的行為。所以在一個(gè)需要多次與特定實(shí)體交互的程序中,就需要維持一個(gè)連接池,里面有可以復(fù)用的連接可供重復(fù)使用。
而維持一個(gè)連接池,最基本的要求就是要做到:thread safe(線程安全),尤其是在Golang這種特性是goroutine的語言中。
實(shí)現(xiàn)簡單的連接池
type Pool struct { m sync.Mutex //保證多個(gè)goroutine訪問時(shí)候,closed的線程安全 res chan io.Closer //連接存儲的chan factory func() (io.Closer,error) //新建連接的工廠方法 closed bool //連接池關(guān)閉標(biāo)志 }
這個(gè)簡單的連接池,我們利用chan來存儲池里的連接。而新建結(jié)構(gòu)體的方法也比較簡單:
func New(fn func() (io.Closer, error), size uint) (*Pool, error) { if size <= 0 { return nil, errors.New("size的值太小了。") } return &Pool{ factory: fn, res: make(chan io.Closer, size), }, nil }
只需要提供對應(yīng)的工廠函數(shù)和連接池的大小就可以了。
獲取連接
那么我們要怎么從中獲取資源呢?因?yàn)槲覀儍?nèi)部存儲連接的結(jié)構(gòu)是chan,所以只需要簡單的select就可以保證線程安全:
//從資源池里獲取一個(gè)資源 func (p *Pool) Acquire() (io.Closer,error) { select { case r,ok := <-p.res: log.Println("Acquire:共享資源") if !ok { return nil,ErrPoolClosed } return r,nil default: log.Println("Acquire:新生成資源") return p.factory() } }
我們先從連接池的res這個(gè)chan里面獲取,如果沒有的話我們就利用我們早已經(jīng)準(zhǔn)備好的工廠函數(shù)進(jìn)行構(gòu)造連接。同時(shí)我們在從res獲取連接的時(shí)候利用ok先確定了這個(gè)連接池是否已經(jīng)關(guān)閉。如果已經(jīng)關(guān)閉的話我們就返回早已經(jīng)準(zhǔn)備好的連接已關(guān)閉錯(cuò)誤。
關(guān)閉連接池
那么既然提到關(guān)閉連接池,我們是怎么樣關(guān)閉連接池的呢?
//關(guān)閉資源池,釋放資源 func (p *Pool) Close() { p.m.Lock() defer p.m.Unlock() if p.closed { return } p.closed = true //關(guān)閉通道,不讓寫入了 close(p.res) //關(guān)閉通道里的資源 for r:=range p.res { r.Close() } }
這邊我們需要先進(jìn)行p.m.Lock()*上鎖操作,這么做是因?yàn)槲覀冃枰獙Y(jié)構(gòu)體里面的*closed進(jìn)行讀寫。需要先把這個(gè)標(biāo)志位設(shè)定后,關(guān)閉res這個(gè)chan,使得Acquire方法無法再獲取新的連接。我們再對res這個(gè)chan里面的連接進(jìn)行Close操作。
釋放連接
釋放連接首先得有個(gè)前提,就是連接池還沒有關(guān)閉。如果連接池已經(jīng)關(guān)閉再往res里面送連接的話就好觸發(fā)panic。
func (p *Pool) Release(r io.Closer){ //保證該操作和Close方法的操作是安全的 p.m.Lock() defer p.m.Unlock() //資源池都關(guān)閉了,就省這一個(gè)沒有釋放的資源了,釋放即可 if p.closed { r.Close() return } select { case p.res <- r: log.Println("資源釋放到池子里了") default: log.Println("資源池滿了,釋放這個(gè)資源吧") r.Close() } }