go通用連接池的實現
簡介
最近寫項目經常需要用到連接池來管理各種連接,連接池的好處在於對頻繁的請求不必單獨創建連接資源,減少cpu及內存消耗。
線程安全
由於獲取連接的請求總是併發的,所以需要考慮到線程安全的問題。其他語言的連接池在獲取連接時需要加鎖來實現共享資源也就是連接池的同步。而go語言卻利用信道,將共享的資源放在信道上進行傳輸,同一時刻只能有一個goroutine擁有該信道。這也是go提倡的一種方式,這種方式編寫的代碼簡潔且效率高。
Do not communicate by sharing memory; instead , share memory by communicating.
代碼實現
下面給出一個通用的go語言連接池的實現
type ConnRes interface {
Close() error
}
type Factory func() (ConnRes,error)
type Pool struct {
conns chan ConnRes
factory Factory
}
func NewPool(factory Factory,cap int) *Pool{
return &Pool{
conns:make(chan ConnRes,cap),
factory:factory,
}
}
func (p *Pool)new() (ConnRes,error){
return p.factory()
}
func (p *Pool) Get() (conn ConnRes){
select {
case conn = <- p.conns:{}
default:
conn, _ = p.new()
}
return
}
func (p *Pool) Put(conn ConnRes){
select {
case p.conns <- conn:{}
default:
conn.Close()
}
}
go語言的可組合性非常強,如上的代碼用簡單的函數對象就能創建不同的連接資源類型。
創建實例
一個連接池的創建可能是這樣的
func main(){
p := NewPool(func() (ConnRes,error) {
return net.Dial("tcp",":8080")
},10)
}
類似於工廠模式,我們不需要明確知道連接類型,只要給定創建該連接類型的函數,我們便可以隨時調用該函數創建連接。
總結
1 接口
go語言的接口與其他語言的接口意義相同,作爲某一種類型的規範或者約定,但go不需要顯式的指定哪個類準從哪一類規範,該類只需要實現該種接口規範的所有方法即可作爲該接口的實現。當然接口也可以作爲實現接口的引用,只不過最終都是由類或者結構體來實現。
2 信道
go語言中的信道是一個高效的用於線程通信的功能,go語言不提倡用線程通信來實現共享內存,因爲大多數時候我們不需要共享內存,我們需要的是線程的同步和通信,所以我們直接使用信道。
3 select
select與信道是密不可分的,運用selec會隨機選擇一個可執行的case進行執行,該原理可能很複雜,信道的很多參數也與select相關。具體實現原理待分析。
4 函數變量
go語言的函數也可以看做一種類型,該類型可作爲參數進行傳遞,在與interface結合使用時有很大的靈活性