golang实现基于channel的通用连接池详解

前言

golang的channel除了goroutine通信之外还有很多其他的功能,本文将实现一种基于channel的通用连接池。下面话不多说了,来一起看看详细的介绍吧。

功能

* 连接池中连接类型为interface{},使得更加通用

* 链接的最大空闲时间,超时的链接将关闭丢弃,可避免空闲时链接自动失效问题

* 使用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等等,非常方便!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

您可能感兴趣的文章:

  • Golang中channel使用的一些小技巧
  • golang中单向channel的语法介绍
(0)

相关推荐

  • golang中单向channel的语法介绍

    本文主要给大家介绍的是关于golang单向channel语法的相关内容,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 今天闲来无事补充一下golang的语法知识,想起来看看context的用法,结果碰到了一个没见过的channel语法: // A Context carries a deadline, cancelation signal, and request-scoped values // across API boundaries. Its methods are sa

  • Golang中channel使用的一些小技巧

    关闭2次 复制代码 代码如下: ch := make(chan bool) close(ch) close(ch)  // 这样会panic的,channel不能close两次 读取的时候channel提前关闭了 复制代码 代码如下: ch := make(chan string) close(ch) i := <- ch // 不会panic, i读取到的值是空 "",  如果channel是bool的,那么读取到的是false 向已经关闭的channel写数据 复制代码 代码

  • golang实现基于channel的通用连接池详解

    前言 golang的channel除了goroutine通信之外还有很多其他的功能,本文将实现一种基于channel的通用连接池.下面话不多说了,来一起看看详细的介绍吧. 功能 * 连接池中连接类型为interface{},使得更加通用 * 链接的最大空闲时间,超时的链接将关闭丢弃,可避免空闲时链接自动失效问题 * 使用channel处理池中的链接,高效 何为通用? 连接池的实现不依赖具体的实例,而依赖某个接口,本文的连接池选用的是io.Closer接口,只要是实现了该接口的对象都可以被池管理.

  • 构建高效的python requests长连接池详解

    前文: 最近在搞全网的CDN刷新系统,在性能调优时遇到了requests长连接的一个问题,以前关注过长连接太多造成浪费的问题,但因为系统都是分布式扩展的,针对这种各别问题就懒得改动了. 现在开发的缓存刷新系统,对于性能还是有些敏感的,我后面会给出最优的http长连接池构建方式. 老生常谈: python下的httpclient库哪个最好用? 我想大多数人还是会选择requests库的.原因么?也就是简单,易用! 如何蛋疼的构建reqeusts的短连接请求: python requests库默认就

  • SpringBoot HikariCP连接池详解

    目录 背景 公用池化包 Commons Pool 2 案例 JMH 测试 数据库连接池 HikariCP 结果缓存池 小结 背景 在我们平常的编码中,通常会将一些对象保存起来,这主要考虑的是对象的创建成本. 比如像线程资源.数据库连接资源或者 TCP 连接等,这类对象的初始化通常要花费比较长的时间,如果频繁地申请和销毁,就会耗费大量的系统资源,造成不必要的性能损失. 并且这些对象都有一个显著的特征,就是通过轻量级的重置工作,可以循环.重复地使用. 这个时候,我们就可以使用一个虚拟的池子,将这些资

  • 如何利用C++实现mysql数据库的连接池详解

    目录 为什么是mysql? 为什么要搞资源池? mysql资源池实现的案例源码 头文件:MysqlPool.h 实现文件:MysqlPool.cpp 测试函数 总结 为什么是mysql? 现在几乎所有的后台应用都要用到数据库,什么关系型的.非关系型的:正当关系的,不正当关系的:主流的和非主流的, 大到Oracle,小到sqlite,以及包括现在逐渐流行的基于物联网的时序数据库,比如涛思的TDengine,咱们中国人自己的开源时序数据库,性能杠杠滴. 凡此总总,即使没用过,也听说过,但大部分人或企

  • Spring Boot如何使用HikariCP连接池详解

    前言 Springboot让Java开发更加美好,更加简洁,更加简单.Spring Boot 2.x中使用HikariCP作为默认的数据连接池. HikariCP使用Javassist字节码操作库来实现动态代理,优化并精简了字节码,同时内部使用 com.zaxxer.hikari.util.FastList 代替ArrayList.使用了更好的并发集合类 com.zaxxer.hikari.util.ConcurrentBag ,"号称"是目前最快的数据库连接池. 下面话不多说了,来一

  • mybatis的动态SQL以及连接池详解

    目录 mybatis动态SQL及连接池 mybatis中的范围查询,in 连接池 动态sql与多表的连接查询 动态sql 多表的连接查询 小结 mybatis动态SQL及连接池 mybatis根据传入参数的不同来查询. <select id="findByCondition" parameterType="com.domain.User" resultType="com.domain.User">         select * f

  • Golang你一定要懂的连接池实现

    问题引入 作为一名Golang开发者,线上环境遇到过好几次连接数暴增问题(mysql/redis/kafka等). 纠其原因,Golang作为常驻进程,请求第三方服务或者资源完毕后,需要手动关闭连接,否则连接会一直存在.而很多时候,开发者不一定记得关闭这个连接. 这样是不是很麻烦?于是有了连接池.顾名思义,连接池就是管理连接的:我们从连接池获取连接,请求完毕后再将连接还给连接池:连接池帮我们做了连接的建立.复用以及回收工作. 在设计与实现连接池时,我们通常需要考虑以下几个问题: 连接池的连接数目

  • 基于tomcat的连接数与线程池详解

    前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xml 中写到过:Connector的主要功能,是接收连接请求,创建Request和Response对象用于和请求端交换数据:然后分配线程让Engine(也就是Servlet容器)来处理这个请求,并把产生的Request和Response对象传给Engine.当Engine处理完请求后,也会通过Conn

  • GoLang channel关闭状态相关操作详解

    关于 channel 的使用,有几点不方便的地方: 1.在不改变 channel 自身状态的情况下,无法获知一个 channel 是否关闭. 2.关闭一个 closed channel 会导致 panic.所以,如果关闭 channel 的一方在不知道 channel 是否处于关闭状态时就去贸然关闭 channel 是很危险的事情. 3.向一个 closed channel 发送数据会导致 panic.所以,如果向 channel 发送数据的一方不知道 channel 是否处于关闭状态时就去贸然

  • 基于NIO的Netty网络框架(详解)

    Netty是一个高性能.异步事件驱动的NIO框架,它提供了对TCP.UDP和文件传输的支持,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果. Netty的优点有: a.功能丰富,内置了多种数据编解码功能.支持多种网络协议. b.高性能,通过与其它主流NIO网络框架对比,它的综合性能最佳. c.可扩展性好,可通过它提供的ChannelHandler组件对网络通信方面进行灵活扩展. d.易用性,API使用简单.

随机推荐