zoukankan      html  css  js  c++  java
  • golang 裸写一个pool池控制协程的大小

    这几天深入的研究了一下golang 的协程,读了一个好文

    http://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mid=2653369770&idx=1&sn=044be64c577a11a9a13447b373e80082&chksm=bce4d5b08b935ca6ad59abb5cc733a341a5126fefc0e6600bd61c959969c5f77c95fbfb909e3&mpshare=1&scene=1&srcid=1010dpu0DlPHi6y1YmrixifX#rd

    就想拿来练手,深入理解了一下,如何控制,协程的大小具体代码如下:

    package main
    
    import (
        "fmt"
        "strconv"
        "time"
        "math/rand"
    )
    
    //声明成游戏
    type Payload struct {
        name string
    }
    //打游戏
    func (p *Payload) Play()  {
        fmt.Printf("%s 打LOL游戏...当前任务完成
    ",p.name)
    }
    
    //任务
    type Job struct {
        Payload Payload
    }
    //任务队列
    var JobQueue chan Job
    
    //  工人
    type Worker struct {
        name string //工人的名字
        // WorkerPool chan JobQueue //对象池
        WorkerPool chan chan Job//对象池
        JobChannel chan Job //通道里面拿
        quit chan bool //
    }
    
    // 新建一个工人
    func NewWorker(workerPool chan chan Job,name string) Worker{
    
        fmt.Printf("创建了一个工人,它的名字是:%s 
    ",name);
        return Worker{
            name:name,//工人的名字
            WorkerPool: workerPool, //工人在哪个对象池里工作,可以理解成部门
            JobChannel:make(chan Job),//工人的任务
            quit:make(chan bool),
        }
    }
    
    // 工人开始工作
    
    func (w *Worker) Start(){
        //开一个新的协程
        go func(){
            for{
                //注册到对象池中,
                w.WorkerPool <-w.JobChannel
                fmt.Printf("[%s]把自己注册到 对象池中 
    ",w.name)
                select {
                //接收到了新的任务
                case job :=<- w.JobChannel:
                    fmt.Printf("[%s] 工人接收到了任务 当前任务的长度是[%d]
    ",w.name,len(w.WorkerPool))
                    job.Payload.Play()
                    time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
                //接收到了任务
                case <-w.quit:
                    return
                }
            }
        }()
    }
    
    func (w Worker) Stop(){
        go func(){
            w.quit <- true
        }()
    }
    
    
    type Dispatcher struct {
                     //WorkerPool chan JobQueue
        name string //调度的名字
        maxWorkers int //获取 调试的大小
        WorkerPool chan chan Job //注册和工人一样的通道
    }
    
    func NewDispatcher(maxWorkers int) *Dispatcher {
        pool :=make(chan chan Job,maxWorkers)
        return &Dispatcher{
            WorkerPool:pool,// 将工人放到一个池中,可以理解成一个部门中
            name:"调度者",//调度者的名字
            maxWorkers:maxWorkers,//这个调度者有好多个工人
        }
    }
    
    func (d *Dispatcher) Run(){
        // 开始运行
        for i :=0;i<d.maxWorkers;i++{
            worker := NewWorker(d.WorkerPool,fmt.Sprintf("work-%s",strconv.Itoa(i)))
            //开始工作
            worker.Start()
        }
        //监控
        go d.dispatch()
    
    }
    
    func (d *Dispatcher) dispatch()  {
        for {
            select {
            case job :=<-JobQueue:
                fmt.Println("调度者,接收到一个工作任务")
                time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
                // 调度者接收到一个工作任务
                go func (job Job) {
                    //从现有的对象池中拿出一个
                    jobChannel := <-d.WorkerPool
    
                    jobChannel <- job
    
                }(job)
            default:
    
                //fmt.Println("ok!!")
            }
    
        }
    }
    
    func initialize()  {
        maxWorkers := 2;
        maxQueue := 4;
        //初始化一个调试者,并指定它可以操作的 工人个数
        dispatch := NewDispatcher(maxWorkers)
        JobQueue =make(chan Job,maxQueue) //指定任务的队列长度
        //并让它一直接运行
        dispatch.Run()
    }
    
    func main() {
        //初始化对象池
        initialize()
        for i:=0;i<10;i++{
            p := Payload{
                fmt.Sprintf("玩家-[%s]",strconv.Itoa(i)),
            }
            JobQueue <- Job{
                Payload:p,
            }
            time.Sleep(time.Second)
        }
        close(JobQueue)
    }

    其实,他的大概思路就是,好比你在一家公司里,你们ceo(main)给你的领导(dispatcher)分配任务,你的领导(dispatcher)再把任务分配给你(worker),你再去执行具体的任务(playload),我理解了好一会,才明白,上面就是一个模子,可以直接复制就可以用

    其中一直不明白 

    var JobQueue chan chan Job
    这个是啥意思,后面在群里问了下,瞬间我就明白了,其实通道的通道,还是通道
  • 相关阅读:
    windows RabbitMQ Server 环境配置中的一些坑
    Redis自定义fastJson Serializer
    如何使用Feign构造多参数的请求
    跨域访问支持(Spring Boot、Nginx、浏览器)
    chrome浏览器的跨域设置
    Jenkins手把手图文教程[基于Jenkins 2.164.1]
    Spring Boot 2发送邮件手把手图文教程
    poi读取Excel模板并修改模板内容与动态的增加行
    Lock类-ReentrantLock的使用
    类ThreadLocal的使用与源码分析
  • 原文地址:https://www.cnblogs.com/jackluo/p/6201862.html
Copyright © 2011-2022 走看看