分享
  1. 首页
  2. 文章

golang通用连接池的实现

xialeistudio · · 9363 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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

何为通用?

连接池的实现不依赖具体的实例,而依赖某个接口,本文的连接池选用的是io.Closer接口,只要是实现了该接口的对象都可以被池管理。
当然,你可以实现基于interface{}的连接池,这样任何对象都可以被管理。

实现原理

将连接句柄存入channel中,由于缓存channel的特性,获取连接时如果池中有连接,将直接返回,如果池中没有连接,将阻塞或者新建连接(没超过最大限制的情况下)。
由于面向接口编程,所有创建连接的逻辑是不清楚的,这里需要传入一个函数,该函数返回一个io.Closer对象。

实现

由于并发问题,在需要操作池中互斥数据的时候需要加锁。

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 // 关闭资源
 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
}

结论

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


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:xialeistudio

查看原文:golang通用连接池的实现

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
9363 次点击
4 回复 | 直到 2021年09月11日 11:27:23
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏