golang 创建一个简单的连接池,减少频繁的创建与关闭

golang 创建一个简单的连接池,减少频繁的创建与关闭,第1张

概述一、连接池的描述图片如下: 二、连接池代码如下: 三、8080服务端代码如下: 测试结果如下:

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

二、连接池代码如下:

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 创建一个简单的连接池,减少频繁的创建与关闭全部内容,希望文章能够帮你解决golang 创建一个简单的连接池,减少频繁的创建与关闭所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1271723.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存