golang 裸写一个pool池控制协程的大小

简介: 这几天深入的研究了一下golang 的协程,读了一个好文 http://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mid=2653369770&idx=1&sn=044be64c577a11a9a13447b373e80082&chksm=bce4d5b0...

这几天深入的研究了一下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游戏...当前任务完成\n",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 \n",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]把自己注册到 对象池中 \n",w.name)
            select {
            //接收到了新的任务
            case job :=<- w.JobChannel:
                fmt.Printf("[%s] 工人接收到了任务 当前任务的长度是[%d]\n",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
这个是啥意思,后面在群里问了下,瞬间我就明白了,其实通道的通道,还是通道

 

目录
相关文章
|
2月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
88 4
|
3月前
|
Go 调度 开发者
[go 面试] 深入理解进程、线程和协程的概念及区别
[go 面试] 深入理解进程、线程和协程的概念及区别
|
18天前
|
存储 安全 测试技术
GoLang协程Goroutiney原理与GMP模型详解
本文详细介绍了Go语言中的Goroutine及其背后的GMP模型。Goroutine是Go语言中的一种轻量级线程,由Go运行时管理,支持高效的并发编程。文章讲解了Goroutine的创建、调度、上下文切换和栈管理等核心机制,并通过示例代码展示了如何使用Goroutine。GMP模型(Goroutine、Processor、Machine)是Go运行时调度Goroutine的基础,通过合理的调度策略,实现了高并发和高性能的程序执行。
77 29
|
16天前
|
Go 计算机视觉
在Golang高并发环境中如何进行协程同步?
在此示例中,使用互斥锁来保护对共享计数器变量 c 的访问,确保并发的 HTTP 请求不会产生数据竞争。
38 3
|
16天前
|
负载均衡 算法 Go
GoLang协程Goroutiney原理与GMP模型详解
【11月更文挑战第4天】Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建和销毁开销小,适合高并发场景。其调度采用非抢占式和协作式多任务处理结合的方式。GMP 模型包括 G(Goroutine)、M(系统线程)和 P(逻辑处理器),通过工作窃取算法实现负载均衡,确保高效利用系统资源。
|
4月前
|
Java Go 调度
GO 协程
GO 协程
36 0
|
1月前
|
安全 Go 调度
探索Go语言的并发模式:协程与通道的协同作用
Go语言以其并发能力闻名于世,而协程(goroutine)和通道(channel)是实现并发的两大利器。本文将深入了解Go语言中协程的轻量级特性,探讨如何利用通道进行协程间的安全通信,并通过实际案例演示如何将这两者结合起来,构建高效且可靠的并发系统。
|
2月前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
53 4
Golang语言goroutine协程篇
|
3月前
|
监控 Devops 测试技术
|
3月前
|
NoSQL Unix 编译器
Golang协程goroutine的调度与状态变迁分析
文章深入分析了Golang中goroutine的调度和状态变迁,包括Grunnable、Gwaiting、Grunning和Gsyscall等状态,以及它们之间的转换条件和原理,帮助理解Go调度器的内部机制。
47 0