前言
golang的channel除了goroutine通信之外還有很多其他的功能,本文將實現(xiàn)一種基于channel的通用連接池。下面話不多說了,來一起看看詳細(xì)的介紹吧。
功能
* 連接池中連接類型為interface{},使得更加通用
* 鏈接的最大空閑時間,超時的鏈接將關(guān)閉丟棄,可避免空閑時鏈接自動失效問題
* 使用channel處理池中的鏈接,高效
何為通用?
連接池的實現(xiàn)不依賴具體的實例,而依賴某個接口,本文的連接池選用的是io.Closer接口,只要是實現(xiàn)了該接口的對象都可以被池管理。
當(dāng)然,你可以實現(xiàn)基于interface{}的連接池,這樣任何對象都可以被管理。
實現(xiàn)原理
將連接句柄存入channel中,由于緩存channel的特性,獲取連接時如果池中有連接,將直接返回,如果池中沒有連接,將阻塞或者新建連接(沒超過最大限制的情況下)。
由于面向接口編程,所有創(chuàng)建連接的邏輯是不清楚的,這里需要傳入一個函數(shù),該函數(shù)返回一個io.Closer對象。
實現(xiàn)
由于并發(fā)問題,在需要操作池中互斥數(shù)據(jù)的時候需要加鎖。
package pool
import (
"errors"
"io"
"sync"
"time"
)
var (
ErrInvalidConfig = errors.New("invalid pool config")
ErrPoolClosed = errors.New("pool closed")
)
type factory func() (io.Closer, error)
type Pool interface {
Acquire() (io.Closer, error) // 獲取資源
Release(io.Closer) error // 釋放資源
Close(io.Closer) error // 關(guān)閉資源
Shutdown() error // 關(guān)閉池
}
type GenericPool struct {
sync.Mutex
pool chan io.Closer
maxOpen int // 池中最大資源數(shù)
numOpen int // 當(dāng)前池中資源數(shù)
minOpen int // 池中最少資源數(shù)
closed bool // 池是否已關(guān)閉
maxLifetime time.Duration
factory factory // 創(chuàng)建連接的方法
}
func NewGenericPool(minOpen, maxOpen int, maxLifetime time.Duration, factory factory) (*GenericPool, error) {
if maxOpen = 0 || minOpen > maxOpen {
return nil, ErrInvalidConfig
}
p := GenericPool{
maxOpen: maxOpen,
minOpen: minOpen,
maxLifetime: maxLifetime,
factory: factory,
pool: make(chan io.Closer, maxOpen),
}
for i := 0; i minOpen; i++ {
closer, err := factory()
if err != nil {
continue
}
p.numOpen++
p.pool - closer
}
return p, nil
}
func (p *GenericPool) Acquire() (io.Closer, error) {
if p.closed {
return nil, ErrPoolClosed
}
for {
closer, err := p.getOrCreate()
if err != nil {
return nil, err
}
// todo maxLifttime處理
return closer, nil
}
}
func (p *GenericPool) getOrCreate() (io.Closer, error) {
select {
case closer := -p.pool:
return closer, nil
default:
}
p.Lock()
if p.numOpen >= p.maxOpen {
closer := -p.pool
p.Unlock()
return closer, nil
}
// 新建連接
closer, err := p.factory()
if err != nil {
p.Unlock()
return nil, err
}
p.numOpen++
p.Unlock()
return closer, nil
}
// 釋放單個資源到連接池
func (p *GenericPool) Release(closer io.Closer) error {
if p.closed {
return ErrPoolClosed
}
p.Lock()
p.pool - closer
p.Unlock()
return nil
}
// 關(guān)閉單個資源
func (p *GenericPool) Close(closer io.Closer) error {
p.Lock()
closer.Close()
p.numOpen--
p.Unlock()
return nil
}
// 關(guān)閉連接池,釋放所有資源
func (p *GenericPool) Shutdown() error {
if p.closed {
return ErrPoolClosed
}
p.Lock()
close(p.pool)
for closer := range p.pool {
closer.Close()
p.numOpen--
}
p.closed = true
p.Unlock()
return nil
}
結(jié)論
基于該連接池,可以管理所有io.Closer對象。比如memcached,redis等等,非常方便!
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
您可能感興趣的文章:- 基于golang channel實現(xiàn)的輕量級異步任務(wù)分發(fā)器示例代碼
- golang中for循環(huán)遍歷channel時需要注意的問題詳解
- Golang優(yōu)雅關(guān)閉channel的方法示例
- golang中單向channel的語法介紹
- golang判斷chan channel是否關(guān)閉的方法
- Golang中channel使用的一些小技巧
- Golang中channel的原理解讀(推薦)