zoukankan      html  css  js  c++  java
  • Go语言-并发模式-goroutine池实例(work)

    介绍

    使用无缓冲的通道来创建一个 goroutine 池,这些 goroutine 执行并控制一组工作,让其并发执行。在这种情况下,使用无缓冲的通道要比随意指定一个缓冲区大小的有缓冲的通道好,因为这个情况下既不需要一个工作队列,也不需要一组 goroutine 配合执行。这种使用无缓冲的通道的方法允许使用者知道什么时候 goroutine 池正在执行工作,而且如果池里的所有goroutine 都忙,无法接受新的工作的时候,也能及时通过通道来通知调用者。使用无缓冲的通道不会有工作在队列里丢失或者卡住,所有工作都会被处理。

    程序

    work.go

    package work
    
    import (
        "sync"
    )
    
    //任务类型接口
    type Worker interface {
        Task(goid int)
    }
    
    //任务池
    type Pool struct {
        work chan Worker
        wg   sync.WaitGroup
    }
    
    //新建
    func New(maxGoroutines int) *Pool {
        //任务池
        p := Pool{
            work: make(chan Worker),
        }
        p.wg.Add(maxGoroutines)
        //创建maxGoroutines个go协程
        for i := 0; i < maxGoroutines; i++ {
            go func(goid int) {
                //保证goroutine不停止执行通道中的任务
                for w := range p.work {
                    w.Task(goid)
                }
                //每个goroutine不再执行work通道中任务时停止
                p.wg.Done()
            }(i)
        }
        return &p
    }
    
    //运行
    func (p *Pool) Run(r Worker) {
        p.work <- r
    }
    
    //停止
    func (p *Pool) Shutdown() {
        close(p.work)
        p.wg.Wait()
    }

    main.go

    package main
    
    import (
        "gopro/patterns/work"
        "log"
        "sync"
        "time"
    )
    
    //
    var names = []string{
        "lili",
        "yingying",
    }
    
    //Worker实现类型
    type namePrinter struct {
        name string
    }
    
    func (n *namePrinter) Task(goid int) {
        log.Printf("goroutineID:%d,打印名字为:%s
    ", goid, n.name)
        time.Sleep(time.Second)
    }
    
    func main() {
        p := work.New(3)
        var wg sync.WaitGroup
        wg.Add(10 * len(names))
    
        for i := 0; i < 10; i++ {
            for _, name := range names {
                //任务实例
                np := namePrinter{
                    name: name,
                }
    
                go func() {
                    p.Run(&np)
                    wg.Done()
                }()
            }
        }
        wg.Wait()
        p.Shutdown()
    }

    执行结果

    2019/06/22 22:55:44 goroutineID:1,打印名字为:lili
    2019/06/22 22:55:44 goroutineID:0,打印名字为:yingying
    2019/06/22 22:55:44 goroutineID:2,打印名字为:yingying
    2019/06/22 22:55:45 goroutineID:0,打印名字为:yingying
    2019/06/22 22:55:45 goroutineID:2,打印名字为:lili
    2019/06/22 22:55:45 goroutineID:1,打印名字为:lili
    2019/06/22 22:55:46 goroutineID:0,打印名字为:yingying
    2019/06/22 22:55:46 goroutineID:2,打印名字为:yingying
    2019/06/22 22:55:46 goroutineID:1,打印名字为:lili
    2019/06/22 22:55:47 goroutineID:2,打印名字为:yingying
    2019/06/22 22:55:47 goroutineID:1,打印名字为:lili
    2019/06/22 22:55:47 goroutineID:0,打印名字为:lili
    2019/06/22 22:55:48 goroutineID:1,打印名字为:lili
    2019/06/22 22:55:48 goroutineID:0,打印名字为:yingying
    2019/06/22 22:55:48 goroutineID:2,打印名字为:yingying
    2019/06/22 22:55:49 goroutineID:2,打印名字为:lili
    2019/06/22 22:55:49 goroutineID:0,打印名字为:yingying
    2019/06/22 22:55:49 goroutineID:1,打印名字为:lili
    2019/06/22 22:55:50 goroutineID:0,打印名字为:lili
    2019/06/22 22:55:50 goroutineID:1,打印名字为:yingying
  • 相关阅读:
    N皇后
    水域大小
    1221 分割平衡字符串
    1391 检查是否存在有效路径 DFS
    盛最多水的容器11 双指针
    烧饼排序
    每日日报8——软件设计④|抽象工厂模式(人与肤色)
    每日日报5——登录功能的实现(JAVA)
    每日日报4——软件设计②|简单工厂模式(女娲造人)
    vue利用transition过渡动画实现轮播图
  • 原文地址:https://www.cnblogs.com/limaosheng/p/11070819.html
Copyright © 2011-2022 走看看