golang 创建一个简单的连接池,减少频繁的创建与关闭
一、连接池的描述图片如下:
二、连接池代码如下:
package main; import (
"time"
"sync"
"errors"
"net"
"fmt"
) //频繁的创建和关闭连接,对系统会造成很大负担
//所以我们需要一个池子,里面事先创建好固定数量的连接资源,需要时就取,不需要就放回池中。
//但是连接资源有一个特点,我们无法保证连接长时间会有效。
//比如,网络原因,人为原因等都会导致连接失效。
//所以我们设置一个超时时间,如果连接时间与当前时间相差超过超时时间,那么就关闭连接。 //只要类型实现了ConnRes接口中的方法,就认为是一个连接资源类型
type ConnRes interface {
Close() error;
} //工厂方法,用于创建连接资源
type Factory func() (ConnRes, error) //连接
type Conn struct {
conn ConnRes;
//连接时间
time time.Time;
} //连接池
type ConnPool struct {
//互斥锁,保证资源安全
mu sync.Mutex;
//通道,保存所有连接资源
conns chan *Conn;
//工厂方法,创建连接资源
factory Factory;
//判断池是否关闭
closed bool;
//连接超时时间
connTimeOut time.Duration;
} //创建一个连接资源池
func NewConnPool(factory Factory, cap int, connTimeOut time.Duration) (*ConnPool, error) {
if cap <= 0 {
return nil, errors.New("cap不能小于0");
}
if connTimeOut <= 0 {
return nil, errors.New("connTimeOut不能小于0");
} cp := &ConnPool{
mu: sync.Mutex{},
conns: make(chan *Conn, cap),
factory: factory,
closed: false,
connTimeOut: connTimeOut,
};
for i := 0; i < cap; i++ {
//通过工厂方法创建连接资源
connRes, err := cp.factory();
if err != nil {
cp.Close();
return nil, errors.New("factory出错");
}
//将连接资源插入通道中
cp.conns <- &Conn{conn: connRes, time: time.Now()};
} return cp, nil;
} //获取连接资源
func (cp *ConnPool) Get() (ConnRes, error) {
if cp.closed {
return nil, errors.New("连接池已关闭");
} for {
select {
//从通道中获取连接资源
case connRes, ok := <-cp.conns:
{
if !ok {
return nil, errors.New("连接池已关闭");
}
//判断连接中的时间,如果超时,则关闭
//继续获取
if time.Now().Sub(connRes.time) > cp.connTimeOut {
connRes.conn.Close();
continue;
}
return connRes.conn, nil;
}
default:
{
//如果无法从通道中获取资源,则重新创建一个资源返回
connRes, err := cp.factory();
if err != nil {
return nil, err;
}
return connRes, nil;
}
}
}
} //连接资源放回池中
func (cp *ConnPool) Put(conn ConnRes) error {
if cp.closed {
return errors.New("连接池已关闭");
} select {
//向通道中加入连接资源
case cp.conns <- &Conn{conn: conn, time: time.Now()}:
{
return nil;
}
default:
{
//如果无法加入,则关闭连接
conn.Close();
return errors.New("连接池已满");
}
}
} //关闭连接池
func (cp *ConnPool) Close() {
if cp.closed {
return;
}
cp.mu.Lock();
cp.closed = true;
//关闭通道
close(cp.conns);
//循环关闭通道中的连接
for conn := range cp.conns {
conn.conn.Close();
}
cp.mu.Unlock();
} //返回池中通道的长度
func (cp *ConnPool) len() int {
return len(cp.conns);
} func main() { cp, _ := NewConnPool(func() (ConnRes, error) {
return net.Dial("tcp", ":8080");
}, 10, time.Second*10); //获取资源
conn1, _ := cp.Get();
conn2, _ := cp.Get(); //这里连接池中资源大小为8
fmt.Println("cp len : ", cp.len());
conn1.(net.Conn).Write([]byte("hello"));
conn2.(net.Conn).Write([]byte("world"));
buf := make([]byte, 1024);
n, _ := conn1.(net.Conn).Read(buf);
fmt.Println("conn1 read : ", string(buf[:n]));
n, _ = conn2.(net.Conn).Read(buf);
fmt.Println("conn2 read : ", string(buf[:n])); //等待15秒
time.Sleep(time.Second * 15);
//我们再从池中获取资源
conn3, _ := cp.Get();
//这里显示为0,因为池中的连接资源都超时了
fmt.Println("cp len : ", cp.len());
conn3.(net.Conn).Write([]byte("test"));
n, _ = conn3.(net.Conn).Read(buf);
fmt.Println("conn3 read : ", string(buf[:n])); //把三个连接资源放回池中
cp.Put(conn1);
cp.Put(conn2);
cp.Put(conn3);
//这里显示为3
fmt.Println("cp len : ", cp.len());
cp.Close();
}
三、8080服务端代码如下:
package main; import (
"net"
"io"
"log"
) func handler(conn net.Conn) {
for {
io.Copy(conn, conn);
}
} func main() {
lis, err := net.Listen("tcp", ":8080");
if err != nil {
log.Fatal(err);
} for {
conn, err := lis.Accept();
if err != nil {
continue;
}
go handler(conn);
}
}
测试结果如下:
golang 创建一个简单的连接池,减少频繁的创建与关闭的更多相关文章
- 用Eclipse 创建一个 简单的 Maven JavaWeb 项目
使用Maven 创建一个简单的 javaWeb 项目: 本篇属于 创建 JavaWeb 项目的第三篇: 建议阅读本篇之前 阅读 用 Eclipse 创建一个简单的web项目 ;本篇是这这篇文章的基础 ...
- Highcharts创建一个简单的柱状图
新建一个html文件,将highcharts引入到你的页面后,通过两个步骤我们就可以创建一个简单的图表了. 1.创建div容器 在页面的 body部分创建一个div,并指定div 的 id,高度和宽度 ...
- 一步一步创建一个简单的Package(1)
创建Package之前首先我们理解需求: 数据源是一组历史货币数据包含在平面文件SampleCurrencyData.txt中,源数据中有四列. 下面是SampleCurrencyData.txt文件 ...
- 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(二)(代码篇)
这篇是上一篇的延续: 用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(一) 源代码在github上可以下载,地址:https://github.com/guoxia ...
- Java网络与多线程系列之1:实现一个简单的对象池
前言 为什么要从对象池开始呢,先从一个网络IO操作的demo说起 比如下面这段代码,显而易见已经在代码中使用了一个固定大小的线程池,所以现在的重点在实现Runnble接口的匿名对象上,这个对象每次创建 ...
- python - DBUtils 连接池减少oracle数据库的连接数
问题: 接到需求,告知项目的oracle连接次数过多,对系统造成太过大的负担,要求减少oracle数据库的连接次数 分析: 仔细分析代码以后,发现产生问题的原因,在于之前要求提升oracle监控的监控 ...
- 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型
第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...
- IOS中TableView的使用(1) -创建一个简单的tableView
创建一个简单的tableView: #import <UIKit/UIKit.h> /*tableView 一定要遵守这两个协议: UITableViewDataSource,UITabl ...
- django创建一个简单的web站点
一.新建project 使用Pycharm,File->New Project…,选择Django,给project命名 (project不能用test命名) 新建的project目录如下: ...
随机推荐
- deb 和 rpm 后缀文件 区别和安装
https://blog.csdn.net/u010977122/article/details/52986217 下载一个ATOM 的deb的安装包
- Incompatible shapes during the half way training---Invalid argument: Incompatible shapes: [1,63,4] vs. [1,64,4]
这是tensorflow model 中我使用它的faster--cnn,但是就是训练过程中,代码执行到一半 一般是step=40~120的时候就报错了: INFO:tensorflow:global ...
- Winform 学生管理系统增删改查
数据库: create database adonet go use adonet go create table xue ( code ), name ), sex bit, birth datet ...
- JVM 图解--1.6,1.7,1.8
- ISE软件报错
ISE弹出如下报错并关闭程序或在编译时出现PATH类报错 一,解决办法 本人自己试了一下 E:\ISE\14.7\ISE_DS\settings64.bat E:\ISE\14.7\ISE_DS\I ...
- python+selenium的环境配置
以前写过关于python和selenium加myeclipse的环境配置,但是myeclipse启动时过于费时,虽然myeclipse有很好的提示功能,但是作为初学者,我还是直接用python的idl ...
- js常用返回网页顶部几种方法
一.使用锚标记 此方法最简单,只需在body下放个隐藏的锚点标记,内容如下: 代码如下 复制代码 <a name="top" id="top">& ...
- 学习DRF之前须知知识点
在学习DRF之前~我们要先复习一些知识点~~ FBV和CBV 学习Django的时候~我们已经学习过了CBV以及FBV~~我们来复习一下~~ 什么是FBV和CBV呢~~ FBV 基于函数的视图 CBV ...
- centos 6.9 +nginx 配置GIT HTTPS服务器(证书采用自签名)
第一部分原通过SSH访问的GIT服务器迁移 1.把原服务器GIT资源库目录完成复制至新的服务器 2.安装GIT服务器 新的服务器 创建用户 useradd git password git 下载GIT ...
- 缩点+最小路径覆盖 hdu 3861
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意:输入t,表示t个样例.接下来每个样例第一行有两个数n,m表示点数和有向边的数量,接下来输入 ...