博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang通用连接池的实现
阅读量:5968 次
发布时间:2019-06-19

本文共 3154 字,大约阅读时间需要 10 分钟。

golang的channel除了goroutine通信之外还有很多其他的功能,本文将实现一种基于channel的通用连接池。

更新

  • 添加超时处理,需要实现GetActiveTime方法获取最后活跃时间。

何为通用?

连接池的实现不依赖具体的实例,而依赖某个接口,本文的连接池选用的是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 Poolable interface {    io.Closer    GetActiveTime() time.Time}type factory func() (Poolable, error)type Pool interface {    Acquire() (Poolable, error) // 获取资源    Release(Poolable) error     // 释放资源    Close(Poolable) error       // 关闭资源    Shutdown() error            // 关闭池}type GenericPool struct {    sync.Mutex    pool        chan Poolable    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 Poolable, 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() (Poolable, error) {    if p.closed {        return nil, ErrPoolClosed    }    for {        closer, err := p.getOrCreate()        if err != nil {            return nil, err        }        // 如果设置了超时且当前连接的活跃时间+超时时间早于现在,则当前连接已过期        if p.maxLifetime > 0 && closer.GetActiveTime().Add(p.maxLifetime).Before(time.Now()) {            p.Close(closer)            continue        }        return closer, nil    }}func (p *GenericPool) getOrCreate() (Poolable, 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 Poolable) error {    if p.closed {        return ErrPoolClosed    }    p.Lock()    p.pool <- closer    p.Unlock()    return nil}// 关闭单个资源func (p *GenericPool) Close(closer Poolable) 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}

结论

基于该连接池,可以管理所有io.Closer对象。比如memcached,redis等等,非常方便!

项目地址

转载地址:http://gatax.baihongyu.com/

你可能感兴趣的文章
HP LaserJet 305X 和 339X 系列一体机如何设置手动或自动接收传真?
查看>>
linux之权限之隐藏权限
查看>>
系统启动时,spring配置文件解析失败,报”cvc-elt.1: 找不到元素 'beans' 的声明“异常...
查看>>
XDCTF成长记录
查看>>
registered the JDBC driver [com.mysql.jdbc.Driver]
查看>>
Linux系统中的文本处理工具
查看>>
IDE---Python IDE之Eric5在window下的安装
查看>>
python---LineReceiver实现记录服务器
查看>>
Mybatis调用Oracle中的存储过程和function
查看>>
telnet :No route to host
查看>>
基本安装lnmp环境
查看>>
yum源资料汇总
查看>>
7、MTC与MTV,http请求介绍
查看>>
logstash消费阿里云kafka消息
查看>>
第四节课作业
查看>>
EasyUI Calendar 日历
查看>>
Oracle 索引
查看>>
数据库复习
查看>>
unix 环境高级编程
查看>>
为数据库建立索引
查看>>