Go语言-并发模式-资源池实例(pool)
Go语言并发模式
利用goroutine和channel进行go的并发模式,实现一个资源池实例(《Go语言实战》书中实例稍作修改)
资源池可以存储一定数量的资源,用户程序从资源池获取资源进行使用,使用完成将资源释放回资源池
程序
pool.go
package pool import (
"errors"
"io"
"log"
"sync"
"time"
) type Pool struct {
m sync.Mutex
resource chan io.Closer
//创建资源的方法,由用户程序自己生成传入
factory func() (io.Closer, error)
closed bool
//资源池获取资源超时时间
timeout <-chan time.Time
} //资源池关闭标志
var ErrPoolClosed = errors.New("资源池已经关闭")
//超时标志
var ErrTimeout = errors.New("获取资源超时") //新建资源池
func New(fn func() (io.Closer, error), size int) (*Pool, error) {
if size <= 0 {
return nil, errors.New("新建资源池大小太小")
}
//新建资源池
p := Pool{
factory: fn,
resource: make(chan io.Closer, size),
}
//向资源池循环添加资源,直到池满
for count := 1; count <= cap(p.resource); count++ {
r, err := fn()
if err != nil {
log.Println("添加资源失败,创建资源方法返回nil")
break
}
log.Println("资源加入资源池")
p.resource <- r
}
log.Println("资源池已满,返回资源池")
return &p, nil
} //获取资源
func (p *Pool) Acquire(d time.Duration) (io.Closer, error) {
//设置d时间后超时
p.timeout = time.After(d)
select {
case r, ok := <-p.resource:
log.Println("获取", "共享资源")
if !ok {
return nil, ErrPoolClosed
}
return r, nil
case <-p.timeout:
return nil, ErrTimeout
}
} //放回资源池
func (p *Pool) Release(r io.Closer) {
//上互斥锁,和Close方法对应,不同时操作
p.m.Lock()
defer p.m.Unlock() if p.closed {
r.Close()
return
}
//资源放回队列
select {
case p.resource <- r:
log.Println("资源放回队列")
default:
log.Println("资源队列已满,释放资源")
r.Close()
}
} //关闭资源池
func (p *Pool) Close() {
//互斥锁,保证同步,和Release方法相关,用同一把锁
p.m.Lock()
defer p.m.Unlock() if p.closed {
return
}
p.closed = true
//清空通道资源之前,将通道关闭,否则引起死锁
close(p.resource)
for r := range p.resource {
r.Close()
}
}
main.go
package main import (
"gopro/patterns/pool"
"io"
"log"
"math/rand"
"sync"
"sync/atomic"
"time"
) const (
maxGoroutines = 25
pooledResources = 2
) //实现接口类型 资源类型
type dbConnection struct {
ID int32
} //实现接口方法
func (conn *dbConnection) Close() error {
log.Printf("资源关闭,ID:%d\n", conn.ID)
return nil
} //给每个连接资源给id
var idCounter int32
//创建新资源
func createConnection() (io.Closer, error) {
id := atomic.AddInt32(&idCounter, 1)
log.Printf("创建新资源,id:%d\n", id)
return &dbConnection{ID: id}, nil
} //测试资源池
func performQueries(query int, p *pool.Pool) {
conn, err := p.Acquire(10 * time.Second)
if err != nil {
log.Println("获取资源超时")
log.Println(err)
return
}
//方法结束后将资源放进资源池
defer p.Release(conn)
//模拟使用资源
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
log.Printf("查询goroutine id:%d,资源ID:%d\n", query, conn.(*dbConnection).ID)
} func main() {
var wg sync.WaitGroup
wg.Add(maxGoroutines) p, err := pool.New(createConnection, pooledResources)
if err != nil {
log.Println(err)
} //每个goroutine一个查询,每个查询从资源池中获取资源
for query := 0; query < maxGoroutines; query++ {
go func(q int) {
performQueries(q, p)
wg.Done()
}(query)
} //主线程等待
wg.Wait()
log.Println("程序结束")
//释放资源
p.Close()
}
执行结果
循环使用两个资源
// :: 创建新资源,id:
// :: 资源加入资源池
// :: 创建新资源,id:
// :: 资源加入资源池
// :: 资源池已满,返回资源池
// :: 获取 共享资源
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 程序结束
// :: 资源关闭,ID:
// :: 资源关闭,ID:
超时结果
修改超时时间为很短
conn, err := p.Acquire( * time.Second)
结果:
// :: 创建新资源,id:
// :: 资源加入资源池
// :: 创建新资源,id:
// :: 资源加入资源池
// :: 资源池已满,返回资源池
// :: 获取 共享资源
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 获取 共享资源
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 获取资源超时
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 查询goroutine id:,资源ID:
// :: 资源放回队列
// :: 程序结束
// :: 资源关闭,ID:
// :: 资源关闭,ID:
Go语言-并发模式-资源池实例(pool)的更多相关文章
- Go语言-并发模式-goroutine池实例(work)
介绍 使用无缓冲的通道来创建一个 goroutine 池,这些 goroutine 执行并控制一组工作,让其并发执行.在这种情况下,使用无缓冲的通道要比随意指定一个缓冲区大小的有缓冲的通道好,因为这个 ...
- 《Go语言实战》摘录:7.2 并发模式 - pool
7.2 并发模式 - pool
- WCF实例上下文模式与并发模式对性能的影响
实例上下文模式 InstanceContextMode 控制在响应客户端调用时,如何分配服务实例.InstanceContextMode 可以设置为以下值: •Single – 为所有客户端调用分配一 ...
- go语言】Goroutines 并发模式
并发模式 让我们先来回顾一下boring函数的例子. func boring(msg string, c chan string) { for i := 0; ; i++ { c ...
- 《Go语言实战》摘录:7.3 并发模式 - work
7.3 并发模式 - work
- 《Go语言实战》摘录:7.1 并发模式 - runner
7.1 并发模式 - runner
- 《C#并发编程经典实例》笔记
1.前言 2.开宗明义 3.开发原则和要点 (1)并发编程概述 (2)异步编程基础 (3)并行开发的基础 (4)测试技巧 (5)集合 (6)函数式OOP (7)同步 1.前言 最近趁着项目的一段平稳期 ...
- Go并发模式:管道与取消
关键字:Go语言,管道,取消机制,并发,sync.WaitGroup,包引用,通道,defer,select GO并发模式:管道与取消 简介 Go的并发能力可以使构建一个流数据管道变得非常容易,并且可 ...
- 09. Go 语言并发
Go 语言并发 并发指在同一时间内可以执行多个任务.并发编程含义比较广泛,包含多线程编程.多进程编程及分布式程序等.本章讲解的并发含义属于多线程编程. Go 语言通过编译器运行时(runtime),从 ...
随机推荐
- pyhton中matplotlib箱线图的绘制(matplotlib双轴图、箱线图、散点图以及相关系数矩阵图))
//2019.07.23 1.箱形图,又称为盒式图,一般可以很好地反映出数据分布的特征,也可以进行多项数据之间分布特征的比较,它主要包含五个基础数据:中位数,两个上下分位数以及上下边缘线数据 其中的一 ...
- python scipy优化器模块(optimize)
pyhton数据处理与分析之scipy优化器及不同函数求根 1.Scipy的优化器模块optimize可以用来求取不同函数在多个约束条件下的最优化问题,也可以用来求取函数在某一点附近的根和对应的函数值 ...
- POJ 3468 区间更新(求任意区间和)A Simple Problem with Integers
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 163977 ...
- 20190108PLC学习心得
应该是数据类型不对 F1查看了帮助文件以后 ,看到 LD应该是用指针类型的数据 改正以后 LD0下的红线消失了 . 绿色 代表没有给 符号 定义 地址 假设 我现在给 符号 字节数 ...
- ArrayList与LindedList区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList ...
- 指令——rm
一个完整的指令的标准格式: Linux通用的格式——#指令主体(空格) [选项](空格) [操作对象] 一个指令可以包含多个选项,操作对象也可以是多个. 指令:rm (remove,移除.删除) 作用 ...
- 微信公众号开发之根据OpenID列表群发(十四)
上一篇我们讲述了<微信公众号开发之根据标签进行群发(十二)>,这次我们讲解一下[根据OpenID列表群发] 根据OpenID列表群发[订阅号不可用,服务号认证后可用] 接口调用请求说明 h ...
- [JZOJ]1293.气象牛[区间DP]
Description 为了研究农场的气候,Betsy帮助农夫John做了N(1 <= N <= 100)次气压测量并按顺序记录了结果M_1-M_N(1 <= M_i <= 1 ...
- Flink 容错机制与状态
简介 Apache Flink提供了一种容错机制,可以持续恢复数据流应用程序的状态. 该机制确保即使出现故障,经过恢复,程序的状态也会回到以前的状态. Flink 主持 at least once 语 ...
- Node.js NPM 包(Package)
章节 Node.js NPM 介绍 Node.js NPM 作用 Node.js NPM 包(Package) Node.js NPM 管理包 Node.js NPM Package.json 包是打 ...