这篇文章给大家介绍golang中怎么利用channel 实现一个连接池,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
何为通用?
连接池的实现不依赖具体的实例,而依赖某个接口,本文的连接池选用的是io.Closer
接口,只要是实现了该接口的对象都可以被池管理。
当然,你可以实现基于interface{}
的连接池,这样任何对象都可以被管理。
将连接句柄存入channel中,由于缓存channel的特性,获取连接时如果池中有连接,将直接返回,如果池中没有连接,将阻塞或者新建连接(没超过最大限制的情况下)。
由于面向接口编程,所有创建连接的逻辑是不清楚的,这里需要传入一个函数,该函数返回一个io.Closer
对象。
由于并发问题,在需要操作池中互斥数据的时候需要加锁。
package poolimport ( "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 // 关闭资源 Shutdown() error // 关闭池}type GenericPool struct { sync.Mutex pool chan io.Closer maxOpen int // 池中最大资源数 numOpen int // 当前池中资源数 minOpen int // 池中最少资源数 closed bool // 池是否已关闭 maxLifetime time.Duration factory factory // 创建连接的方法}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}// 关闭单个资源func (p *GenericPool) Close(closer io.Closer) error { p.Lock() closer.Close() p.numOpen-- p.Unlock() return nil}// 关闭连接池,释放所有资源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}
关于golang中怎么利用channel 实现一个连接池就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4586289/blog/4634674