go的pool资源池:
1.当有多个并发请求的时候,比如需要查询数据库
2.先创建一个2个容量的数据库连接资源池
3.当一个请求过来的时候,去资源池里请求连接资源,肯定是空的就创建一个连接,执行查询,结束后放入了资源池里
4.当第二个请求过来的时候,也是去资源池请求连接资源,就直接在池中拿过来一个连接进行查询
5.当并发大的时候,资源池里面没有足够连接资源,就会不停创建新资源,放入池里面的时候,也会放不进去,就主动关闭掉这个资源
6.这里的资源池实质上是一个缓冲通道,里面放着连接资源

package main

import (
"errors"
"io"
"log"
"math/rand"
"sync"
"sync/atomic"
"time"
) //定义一个结构体,这个实体类型可以作为整体单元被复制,可以作为参数或返回值,或被存储到数组
type Pool struct {
//定义成员,互斥锁类型
m sync.Mutex
//定义成员,通道类型,通道传递的是io.Closer类型
resources chan io.Closer
//定义工厂成员,类型是func()(io.Closer,error)
//error是预定义类型,实际上是个interface接口类型
factory func() (io.Closer, error)
closed bool
} //定义变量,函数返回的是error类型
var ErrPoolClosed = errors.New("池已经关闭了") //定义New方法,创建一个池,返回的是Pool类型的指针
//传入的参数是个函数类型func(io.Closer,error)和池的大小
func New(fn func() (io.Closer, error), size uint) (*Pool, error) {
//使用结构体字面值给结构体成员赋值
myPool := Pool{
factory: fn,
resources: make(chan io.Closer, size),
}
//返回两个返回值
return &myPool, nil
} //从池中请求获取一个资源,给Pool类型定义的方法
//返回的值是io.Closer类型
func (p *Pool) Acquire() (io.Closer, error) {
//基于select的多路复用
//select会等待case中有能够执行的,才会去执行,等待其中一个能执行就执行
//default分支会在所有case没法执行时,默认执行,也叫轮询channel
select {
case r, _ := <-p.resources:
log.Printf("请求资源:来自通道 %d", r.(*dbConn).ID)
return r, nil
//如果缓冲通道中没有了,就会执行这里
default:
log.Printf("请求资源:创建新资源")
return p.factory()
}
} //将一个使用后的资源放回池
//传入的参数是io.Closer类型
func (p *Pool) Release(r io.Closer) {
//使用mutex互斥锁
p.m.Lock()
//解锁
defer p.m.Unlock()
//如果池都关闭了
if p.closed {
//关掉资源
r.Close()
return
}
//select多路选择
//如果放回通道的时候满了,就关闭这个资源
select {
case p.resources <- r:
log.Printf("释放资源:放入通道 %d", r.(*dbConn).ID)
default:
log.Printf("释放资源:关闭资源%d", r.(*dbConn).ID)
r.Close()
}
} //关闭资源池,关闭通道,将通道中的资源关掉
func (p *Pool) Close() {
p.m.Lock()
defer p.m.Unlock()
p.closed = true
//先关闭通道再清空资源
close(p.resources)
//清空并关闭资源
for r := range p.resources {
r.Close()
}
} //定义全局常量
const (
maxGoroutines = 20 //使用25个goroutine模拟同时的连接请求
poolSize = 2 //资源池中的大小
) //定义结构体,模拟要共享的资源
type dbConn struct {
//定义成员
ID int32
} //dbConn实现io.Closer接口
func (db *dbConn) Close() error {
return nil
} var idCounter int32 //定义一个全局的共享的变量,更新时用原子函数锁住
//定义方法,创建dbConn实例
//返回的是io.Closer类型和error类型
func createConn() (io.Closer, error) {
//原子函数锁住,更新加1
id := atomic.AddInt32(&idCounter, 1)
log.Printf("创建新资源: %d", id)
return &dbConn{id}, nil
}
func main() {
//计数信号量
var wg sync.WaitGroup
//同时并发的数量
wg.Add(maxGoroutines)
myPool, _ := New(createConn, poolSize)
//开25个goroutine同时查询
for i := 0; i < maxGoroutines; i++ {
//模拟请求
time.Sleep(time.Duration(rand.Intn(2)) * time.Second)
go func(gid int) {
execQuery(gid, myPool)
wg.Done()
}(i)
}
//等待上面开的goroutine结束
wg.Wait()
myPool.Close()
} //定义一个查询方法,参数是当前gorotineId和资源池
func execQuery(goroutineId int, pool *Pool) {
//从池里请求资源,第一次肯定是没有的,就会创建一个dbConn实例
conn, _ := pool.Acquire()
//将创建的dbConn实例放入了资源池的缓冲通道里
defer pool.Release(conn)
//睡眠一下,模拟查询过程
time.Sleep(time.Duration(rand.Intn(10)) * time.Second)
log.Printf("执行查询...协程ID [%d] 资源ID [%d]", goroutineId, conn.(*dbConn).ID)
}

  

[Go] golang缓冲通道实现资源池的更多相关文章

  1. [Go] golang缓冲通道实现管理一组goroutine工作

    通道1.当一个资源需要在goroutine之间共享时,通道在goroutine之间架起了一个管道2.无缓冲通道和有缓冲通道,make的第二个参数就是缓冲区大小3.无缓冲通道需要发送和接收都准备好,否则 ...

  2. golang channel无缓冲通道会发生阻塞的验证

    公司搞了午间技术par,本周我讲的主题是关于无缓冲通道channel是否会发生阻塞,并进行了验证. go语言中channel分为无缓冲通道和有缓冲通道两种 channel提供了一种在goroutine ...

  3. [Go] golang无缓冲通道实现工作池控制并发

    展示如何使用无缓冲的通道创建一个goroutine池,控制并发频率1.无缓冲通道保证了两个goroutine之间的数据交换2.当所有的goroutine都忙的时候,能够及时通过通道告知调用者3.无缓冲 ...

  4. Golang并发编程有缓冲通道和无缓冲通道(channel)

    无缓冲通道 是指在接收前没有能力保存任何值得通道.这种类型的通道要求发送goroutine和接收goroutine同时准备好,才能完成发送和接收操作.如果两个goroutine没有同时准备好,通道会导 ...

  5. golang中为何在同一个goroutine中使用无缓冲通道会导致死锁

    package main import "fmt" func main() { /* 以下程序会导致死锁 c := make(chan int) c <- 10 n1 := ...

  6. Go语言的通道(2)-缓冲通道

    有缓冲的通道相比于无缓冲通道,多了一个缓存的功能,如下图描述的一样: 从图上可以明显看到和无缓冲通道的区别,无缓冲必须两个Goroutine都进入通道才能进行数据的交换,这个不用,如果数据有,直接就能 ...

  7. Go语言的通道(1)-无缓冲通道

    前言: 上文中我们采用了[原子函数]已经[共享锁]两种方式分别对多个goroutine进行了同步,但是在go语言中提供了另一种更好的方式,那就是使用通道(Channel). 一.通道是什么? 其实无论 ...

  8. [GO]有缓冲通道

    有缓冲通道就是在有能力保留数据的通道,那么通道在满的时候或者通道是空的时候,存数据和取数据就会发生阻塞 package main import ( "fmt" "time ...

  9. [GO]无缓冲通道(unbuffered channel)

    无缓冲通道(unbuffered channel)是指在接收前没有能力保存任何值的通道,在之前的例子中使用的都是无缓冲通道,需要注意的是,对于无缓冲通道而言,不管是往通道里写数据还是从通道里读数据,都 ...

随机推荐

  1. 关于postgresql group by 报错

    举个例子:     table name:makerar cname  | wmname |          avg            --------+-------------+------ ...

  2. [微信小程序]编译.wxss出错,2 not found

    小程序新建项目就出错:2 not found  编译.wxss文件出错(不是一般的郁闷,新建项目就报错...) 大概的情况是开发工具没有更新.或更新不到, 第一,可以删掉开发工具重新下载最新安装: 第 ...

  3. Android找回密码功能 手机找回、邮箱找回

    找回密码功能设计:https://blog.csdn.net/qq_33472765/article/details/82287404?utm_source=blogxgwz0 手机找回:https: ...

  4. Python基础之迭代器、生成器

    一.迭代器: 1.迭代:每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值.例如:循环获取容器中的元素. 2.可迭代对象(iterable): 1)定义:具有__ite ...

  5. 写书好累 <HTTP抓包实战>终于出版

    我的新书<HTTP抓包实战>终于开始在京东销售了.内容是关于HTTP包,Fiddler抓包,JMeter发包,适合任何IT工程师阅读.我将自己十年所学的知识,融会贯通总结为一本书.阅读后肯 ...

  6. js 格式化数字,格式化金额:

    js 格式化数字,格式化金额: function number_format(number, decimals, dec_point, thousands_sep) { /* * 参数说明: * nu ...

  7. 【RL-TCPnet网络教程】第29章 NTP网络时间协议基础知识

    第29章      NTP网络时间协议基础知识 本章节为大家讲解NTP (Network Time Protocol,网络时间协议)和SNTP(简单网络时间协议,Simple Network Time ...

  8. CAS实现单点登录SSO执行原理及部署

    一.不落俗套的开始 1.背景介绍 单点登录:Single Sign On,简称SSO,SSO使得在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. CAS框架:CAS(Centra ...

  9. [Swift]LeetCode41. 缺失的第一个正数 | First Missing Positive

    Given an unsorted integer array, find the smallest missing positive integer. Example 1: Input: [1,2, ...

  10. [Swift]LeetCode246.对称数 $ Strobogrammatic Number

    A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside ...