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
", conn.ID)
    return nil
}

//给每个连接资源给id
var idCounter int32
//创建新资源
func createConnection() (io.Closer, error) {
    id := atomic.AddInt32(&idCounter, 1)
    log.Printf("创建新资源,id:%d
", 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
", 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()
}

执行结果

循环使用两个资源

2019/06/21 00:45:34 创建新资源,id:1
2019/06/21 00:45:34 资源加入资源池
2019/06/21 00:45:34 创建新资源,id:2
2019/06/21 00:45:34 资源加入资源池
2019/06/21 00:45:34 资源池已满,返回资源池
2019/06/21 00:45:34 获取 共享资源
2019/06/21 00:45:34 获取 共享资源
2019/06/21 00:45:34 查询goroutine id:1,资源ID:1
2019/06/21 00:45:34 资源放回队列
2019/06/21 00:45:34 获取 共享资源
2019/06/21 00:45:35 查询goroutine id:0,资源ID:2
2019/06/21 00:45:35 资源放回队列
2019/06/21 00:45:35 获取 共享资源
2019/06/21 00:45:35 查询goroutine id:4,资源ID:1
2019/06/21 00:45:35 资源放回队列
2019/06/21 00:45:35 获取 共享资源
2019/06/21 00:45:35 查询goroutine id:24,资源ID:2
2019/06/21 00:45:35 资源放回队列
2019/06/21 00:45:35 获取 共享资源
2019/06/21 00:45:35 查询goroutine id:3,资源ID:1
2019/06/21 00:45:35 资源放回队列
2019/06/21 00:45:35 获取 共享资源
2019/06/21 00:45:35 查询goroutine id:14,资源ID:2
2019/06/21 00:45:35 资源放回队列
2019/06/21 00:45:35 获取 共享资源
2019/06/21 00:45:35 查询goroutine id:5,资源ID:1
2019/06/21 00:45:35 资源放回队列
2019/06/21 00:45:35 获取 共享资源
2019/06/21 00:45:35 查询goroutine id:6,资源ID:2
2019/06/21 00:45:35 资源放回队列
2019/06/21 00:45:35 获取 共享资源
2019/06/21 00:45:36 查询goroutine id:7,资源ID:1
2019/06/21 00:45:36 资源放回队列
2019/06/21 00:45:36 获取 共享资源
2019/06/21 00:45:36 查询goroutine id:8,资源ID:2
2019/06/21 00:45:36 资源放回队列
2019/06/21 00:45:36 获取 共享资源
2019/06/21 00:45:36 查询goroutine id:9,资源ID:1
2019/06/21 00:45:36 资源放回队列
2019/06/21 00:45:36 获取 共享资源
2019/06/21 00:45:36 查询goroutine id:10,资源ID:2
2019/06/21 00:45:36 资源放回队列
2019/06/21 00:45:36 获取 共享资源
2019/06/21 00:45:36 查询goroutine id:12,资源ID:2
2019/06/21 00:45:36 资源放回队列
2019/06/21 00:45:36 获取 共享资源
2019/06/21 00:45:36 查询goroutine id:11,资源ID:1
2019/06/21 00:45:36 资源放回队列
2019/06/21 00:45:36 获取 共享资源
2019/06/21 00:45:37 查询goroutine id:15,资源ID:1
2019/06/21 00:45:37 资源放回队列
2019/06/21 00:45:37 获取 共享资源
2019/06/21 00:45:37 查询goroutine id:20,资源ID:1
2019/06/21 00:45:37 资源放回队列
2019/06/21 00:45:37 获取 共享资源
2019/06/21 00:45:37 查询goroutine id:13,资源ID:2
2019/06/21 00:45:37 资源放回队列
2019/06/21 00:45:37 获取 共享资源
2019/06/21 00:45:37 查询goroutine id:16,资源ID:2
2019/06/21 00:45:37 资源放回队列
2019/06/21 00:45:37 获取 共享资源
2019/06/21 00:45:37 查询goroutine id:19,资源ID:1
2019/06/21 00:45:37 资源放回队列
2019/06/21 00:45:37 获取 共享资源
2019/06/21 00:45:37 查询goroutine id:21,资源ID:2
2019/06/21 00:45:37 资源放回队列
2019/06/21 00:45:37 获取 共享资源
2019/06/21 00:45:38 查询goroutine id:17,资源ID:1
2019/06/21 00:45:38 资源放回队列
2019/06/21 00:45:38 获取 共享资源
2019/06/21 00:45:38 查询goroutine id:22,资源ID:2
2019/06/21 00:45:38 资源放回队列
2019/06/21 00:45:38 获取 共享资源
2019/06/21 00:45:38 查询goroutine id:23,资源ID:2
2019/06/21 00:45:38 资源放回队列
2019/06/21 00:45:38 获取 共享资源
2019/06/21 00:45:38 查询goroutine id:2,资源ID:2
2019/06/21 00:45:38 资源放回队列
2019/06/21 00:45:38 查询goroutine id:18,资源ID:1
2019/06/21 00:45:38 资源放回队列
2019/06/21 00:45:38 程序结束
2019/06/21 00:45:38 资源关闭,ID:2
2019/06/21 00:45:38 资源关闭,ID:1

超时结果

修改超时时间为很短 

conn, err := p.Acquire(2 * time.Second)

结果:

2019/06/21 00:58:33 创建新资源,id:1
2019/06/21 00:58:33 资源加入资源池
2019/06/21 00:58:33 创建新资源,id:2
2019/06/21 00:58:33 资源加入资源池
2019/06/21 00:58:33 资源池已满,返回资源池
2019/06/21 00:58:33 获取 共享资源
2019/06/21 00:58:33 获取 共享资源
2019/06/21 00:58:33 查询goroutine id:0,资源ID:1
2019/06/21 00:58:33 资源放回队列
2019/06/21 00:58:33 获取 共享资源
2019/06/21 00:58:34 查询goroutine id:5,资源ID:2
2019/06/21 00:58:34 资源放回队列
2019/06/21 00:58:34 获取 共享资源
2019/06/21 00:58:34 查询goroutine id:24,资源ID:1
2019/06/21 00:58:34 资源放回队列
2019/06/21 00:58:34 获取 共享资源
2019/06/21 00:58:34 查询goroutine id:11,资源ID:2
2019/06/21 00:58:34 资源放回队列
2019/06/21 00:58:34 获取 共享资源
2019/06/21 00:58:34 查询goroutine id:1,资源ID:1
2019/06/21 00:58:34 资源放回队列
2019/06/21 00:58:34 获取 共享资源
2019/06/21 00:58:34 查询goroutine id:2,资源ID:2
2019/06/21 00:58:34 资源放回队列
2019/06/21 00:58:34 获取 共享资源
2019/06/21 00:58:34 查询goroutine id:3,资源ID:1
2019/06/21 00:58:34 资源放回队列
2019/06/21 00:58:34 获取 共享资源
2019/06/21 00:58:34 查询goroutine id:4,资源ID:2
2019/06/21 00:58:34 资源放回队列
2019/06/21 00:58:34 获取 共享资源
2019/06/21 00:58:35 查询goroutine id:17,资源ID:1
2019/06/21 00:58:35 资源放回队列
2019/06/21 00:58:35 获取 共享资源
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 获取资源超时
2019/06/21 00:58:35 查询goroutine id:12,资源ID:2
2019/06/21 00:58:35 资源放回队列
2019/06/21 00:58:35 查询goroutine id:13,资源ID:1
2019/06/21 00:58:35 资源放回队列
2019/06/21 00:58:35 程序结束
2019/06/21 00:58:35 资源关闭,ID:2
2019/06/21 00:58:35 资源关闭,ID:1
原文地址:https://www.cnblogs.com/limaosheng/p/11062338.html