Golang语言社区--golang通用连接池的实现

golang的channel除了goroutine通信之外还有很多其他的功能,本文将实现一种基于channel的通用连接池。
何为通用?
连接池的实现不依赖具体的实例,而依赖某个接口,本文的连接池选用的是io.Closer接口,只要是实现了该接口的对象都可以被池管理。
当然,你可以实现基于interface{}的连接池,这样任何对象都可以被管理。
实现原理
将连接句柄存入channel中,由于缓存channel的特性,获取连接时如果池中有连接,将直接返回,如果池中没有连接,将阻塞或者新建连接(没超过最大限制的情况下)。
由于面向接口编程,所有创建连接的逻辑是不清楚的,这里需要传入一个函数,该函数返回一个io.Closer对象。
实现
由于并发问题,在需要操作池中互斥数据的时候需要加锁。
  1. package pool

  2. import (
  3.     "errors"
  4.     "io"
  5.     "sync"
  6.     "time"
  7. )

  8. var (
  9.     ErrInvalidConfig = errors.New("invalid pool config")
  10.     ErrPoolClosed    = errors.New("pool closed")
  11. )

  12. type factory func() (io.Closer, error)

  13. type Pool interface {
  14.     Acquire() (io.Closer, error) // 获取资源
  15.     Release(io.Closer) error     // 释放资源
  16.     Close(io.Closer) error       // 关闭资源
  17.     Shutdown() error             // 关闭池
  18. }

  19. type GenericPool struct {
  20.     sync.Mutex
  21.     pool        chan io.Closer
  22.     maxOpen     int  // 池中最大资源数
  23.     numOpen     int  // 当前池中资源数
  24.     minOpen     int  // 池中最少资源数
  25.     closed      bool // 池是否已关闭
  26.     maxLifetime time.Duration
  27.     factory     factory // 创建连接的方法
  28. }

  29. func NewGenericPool(minOpen, maxOpen int, maxLifetime time.Duration, factory factory) (*GenericPool, error) {
  30.     if maxOpen <= 0 || minOpen > maxOpen {
  31.         return nil, ErrInvalidConfig
  32.     }
  33.     p := &GenericPool{
  34.         maxOpen:     maxOpen,
  35.         minOpen:     minOpen,
  36.         maxLifetime: maxLifetime,
  37.         factory:     factory,
  38.         pool:        make(chan io.Closer, maxOpen),
  39.     }

  40.     for i := 0; i < minOpen; i++ {
  41.         closer, err := factory()
  42.         if err != nil {
  43.             continue
  44.         }
  45.         p.numOpen++
  46.         p.pool <- closer
  47.     }
  48.     return p, nil
  49. }

  50. func (p *GenericPool) Acquire() (io.Closer, error) {
  51.     if p.closed {
  52.         return nil, ErrPoolClosed
  53.     }
  54.     for {
  55.         closer, err := p.getOrCreate()
  56.         if err != nil {
  57.             return nil, err
  58.         }
  59.         // todo maxLifttime处理
  60.         return closer, nil
  61.     }
  62. }

  63. func (p *GenericPool) getOrCreate() (io.Closer, error) {
  64.     select {
  65.     case closer := <-p.pool:
  66.         return closer, nil
  67.     default:
  68.     }
  69.     p.Lock()
  70.     if p.numOpen >= p.maxOpen {
  71.         closer := <-p.pool
  72.         p.Unlock()
  73.         return closer, nil
  74.     }
  75.     // 新建连接
  76.     closer, err := p.factory()
  77.     if err != nil {
  78.         p.Unlock()
  79.         return nil, err
  80.     }
  81.     p.numOpen++
  82.     p.Unlock()
  83.     return closer, nil
  84. }

  85. // 释放单个资源到连接池
  86. func (p *GenericPool) Release(closer io.Closer) error {
  87.     if p.closed {
  88.         return ErrPoolClosed
  89.     }
  90.     p.Lock()
  91.     p.pool <- closer
  92.     p.Unlock()
  93.     return nil
  94. }

  95. // 关闭单个资源
  96. func (p *GenericPool) Close(closer io.Closer) error {
  97.     p.Lock()
  98.     closer.Close()
  99.     p.numOpen--
  100.     p.Unlock()
  101.     return nil
  102. }

  103. // 关闭连接池,释放所有资源
  104. func (p *GenericPool) Shutdown() error {
  105.     if p.closed {
  106.         return ErrPoolClosed
  107.     }
  108.     p.Lock()
  109.     close(p.pool)
  110.     for closer := range p.pool {
  111.         closer.Close()
  112.         p.numOpen--
  113.     }
  114.     p.closed = true
  115.     p.Unlock()
  116.     return nil
  117. }
复制代码
结论
基于该连接池,可以管理所有io.Closer对象。比如memcached,redis等等,非常方便!

Golang语言社区论坛网址:www.golang.ltd

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Go中实现RabbitMQ的连接池,你可以使用`github.com/streadway/amqp`库结合`sync.Pool`来管理连接对象。这是一个简单的连接池实现示例: ```go import ( "github.com/streadway/amqp" "sync" ) type RabbitMQPool struct { connStr string pool *sync.Pool } func NewRabbitMQPool(connStr string) *RabbitMQPool { return &RabbitMQPool{ connStr: connStr, pool: &sync.Pool{ New: func() interface{} { conn, err := amqp.Dial(connStr) if err != nil { panic(err) // 处理连接错误,这里简单起见直接panic } return conn }, }, } } func (p *RabbitMQPool) GetConnection() *amqp.Connection { return p.pool.Get().(*amqp.Connection) } func (p *RabbitMQPool) ReleaseConnection(conn *amqp.Connection) { p.pool.Put(conn) } ``` 在上面的示例中,`RabbitMQPool`结构体代表了一个RabbitMQ连接池。`NewRabbitMQPool`函数用于创建一个新的连接池对象,传入RabbitMQ的连接字符串作为参数。 `GetConnection`方法用于从连接池中获取一个可用的连接对象。`ReleaseConnection`方法用于将连接对象放回连接池中。 这样,你就可以在你的代码中使用连接池来获取和释放RabbitMQ连接,而无需每次都重新创建和关闭连接。例如: ```go pool := NewRabbitMQPool("amqp://guest:guest@localhost:5672/") // 获取连接 conn := pool.GetConnection() defer pool.ReleaseConnection(conn) // 使用连接进行操作,比如发送消息等 // ... ``` 记得在适当的地方处理连接错误和关闭连接。 请注意,这只是一个简单的示例,你可以根据你的实际需求进行适当的修改和扩展,比如添加连接的最大数量、定时检查连接状态等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值