一、连接池的描述图片如下:

二、连接池代码如下:

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 创建一个简单的连接池,减少频繁的创建与关闭的更多相关文章

  1. 用Eclipse 创建一个 简单的 Maven JavaWeb 项目

    使用Maven 创建一个简单的 javaWeb 项目: 本篇属于 创建 JavaWeb 项目的第三篇: 建议阅读本篇之前 阅读 用 Eclipse 创建一个简单的web项目  ;本篇是这这篇文章的基础 ...

  2. Highcharts创建一个简单的柱状图

    新建一个html文件,将highcharts引入到你的页面后,通过两个步骤我们就可以创建一个简单的图表了. 1.创建div容器 在页面的 body部分创建一个div,并指定div 的 id,高度和宽度 ...

  3. 一步一步创建一个简单的Package(1)

    创建Package之前首先我们理解需求: 数据源是一组历史货币数据包含在平面文件SampleCurrencyData.txt中,源数据中有四列. 下面是SampleCurrencyData.txt文件 ...

  4. 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(二)(代码篇)

    这篇是上一篇的延续: 用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(一) 源代码在github上可以下载,地址:https://github.com/guoxia ...

  5. Java网络与多线程系列之1:实现一个简单的对象池

    前言 为什么要从对象池开始呢,先从一个网络IO操作的demo说起 比如下面这段代码,显而易见已经在代码中使用了一个固定大小的线程池,所以现在的重点在实现Runnble接口的匿名对象上,这个对象每次创建 ...

  6. python - DBUtils 连接池减少oracle数据库的连接数

    问题: 接到需求,告知项目的oracle连接次数过多,对系统造成太过大的负担,要求减少oracle数据库的连接次数 分析: 仔细分析代码以后,发现产生问题的原因,在于之前要求提升oracle监控的监控 ...

  7. 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型

    第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...

  8. IOS中TableView的使用(1) -创建一个简单的tableView

    创建一个简单的tableView: #import <UIKit/UIKit.h> /*tableView 一定要遵守这两个协议: UITableViewDataSource,UITabl ...

  9. django创建一个简单的web站点

    一.新建project 使用Pycharm,File->New Project…,选择Django,给project命名 (project不能用test命名)   新建的project目录如下: ...

随机推荐

  1. 安装安卓SDK和JDK的简便方法

    直接在VS的安装程序里选:使用.NET的移动开发,其中就包括了安卓SDK,JAVA SE等 另外:自己手动安装SDK时,不要选模拟器相关的东西,太大了,如果每个版本都选,安装下来上100G以上

  2. Visual SVN Server备份脚本

    set tt=%date:~0,4%%date:~5,2%%date:~8,2% mkdir D:\SVN_BACKUP_%tt%\Repositories xcopy C:\Repositories ...

  3. centos7启动iptables时报Job for iptables.service failed because the control process exited with error cod

    centos7启动iptables时报Job for iptables.service failed because the control process exited with error cod ...

  4. Django后台邮箱配置

    Django可以通过发送邮件的方式找回密码,具体细节可以看Django的文档,这里只介绍在settings.py中如何正确进行邮箱的相关配置. 网上很多教程都说了需要在settings.py里添加如下 ...

  5. springboot 整合task定时任务

    一步:在启动类中加入     加入就会调用定时了. //开启定时任务 开启后就可以被扫描到   @EnableScheduling 二步:建一个tasks工具包 都会被扫描到的了 有三个类 Async ...

  6. swift中的UITextField

    let userTF = UITextField(frame: CGRectMake(,,,)) userTF.backgroundColor = UIColor.redColor() // 输入框样 ...

  7. PR(Precision-Recall)曲线和mAP指标

    来自: https://www.zhihu.com/question/41540197 https://www.douban.com/note/518998773/ 作者:水哥链接:https://w ...

  8. hadoop2.7.7 测试安装 centos7

    useradd –m hadoop –s /bin/bash passwd hadoop   增加sudo权限 chmod u+w /etc/sudoers vi /etc/sudoers root ...

  9. node Cannot enqueue Quit after invoking quit.

    因为第二次调用数据库时连接关闭了,应该把connection.connect();放在请求的函数里面:不然第二次请求出错

  10. w3af安装

    基于python开发,由于kali自带的w3af无法正常使用 安装新的w3af apt-get update apt-get install kali-linux-all安装所有工具包 apt-get ...