温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

golang中怎么利用channel 实现一个连接池

发布时间:2021-07-06 15:13:30 阅读:242 作者:Leah 栏目:大数据
GO开发者专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

这篇文章给大家介绍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元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/u/4586289/blog/4634674

AI

开发者交流群×