jobpool: 待处理任务队列
workerpool: 空闲处理者队列
job: 任务类
worker: 处理者类
go: jobpool在前面不断的接收job(jobpool <- job)
go: for: worker从jobpool里循环获取job来处理(select {case job := <-jobpool),
go: 当来一条job时,就会在workerpool中拿一个空闲的Worker去处理该job,同时此worker在workerpool里消失,
待此worker处理完后,又会workerpool <- worker(加入到空闲worker队里)。
当工作池中没有可用的worker时,就会阻塞等待一个空闲的worker(select {case worker := <-wp.WorkerQueue...)
jobpool中如果定义最多放num个待处理的job,就会最多启num个gorouter。
如果jobpool中要定义最多放5 × num个待处理的job,而只允许最多启num个gorouter的话,可设置最大线程数:debug.SetMaxThreads(num)。
// jobpool在前面不断的接收job
go func() {
for i := 1; i <= num; i++ {
job := &Job{}
jobpool <- job
}
}()
// 循环获取可用的worker,为其分配job来处理
go func() {
for {
select {
case job := <-wp.JobQueue: // 获取待处理的job
select {
case worker := <-wp.WorkerQueue: // 获取空闲的worker
go worker.run(job) // 此worker处理此job
}
}
}
}()
原: (转自:https://studygolang.com/articles/17711)
整个过程中,每个Worker都会被运行在一个协程中,
在整个WorkerPool中就会有num个空闲的Worker,
当来一条数据的时候,就会在工作池中去一个空闲的Worker去执行该Job,
当工作池中没有可用的worker时,就会阻塞等待一个空闲的worker。
原code:
[main.go]
package main
import (
"fmt"
"runtime"
"time"
)
type Score struct {
Num int
}
func (s *Score) Do() {
fmt.Println("num:", s.Num)
time.Sleep(1 * 1 * time.Second)
}
func main() {
num := 100 * 100 * 20
// debug.SetMaxThreads(num + 1000) //设置最大线程数
//当数据无限多的时候func (wp *WorkerPool) Run() 会无限创建协程,这里需要做一些处理
// 注册工作池(待处理队列)
p := NewWorkerPool(num) // num为worker并发个数,即任务处理者个数
p.Run()
// 往待处理队列里传入任务
datanum := 100 * 100 * 100 * 100
go func() {
for i := 1; i <= datanum; i++ {
sc := &Score{Num: i}
p.JobQueue <- sc
}
}()
for {
fmt.Println("runtime.NumGoroutine() :", runtime.NumGoroutine())
time.Sleep(2 * time.Second)
}
}
[job.go]
package main
type Job interface {
Do()
}
[worker.go]
package main
type Worker struct {
JobQueue chan Job
}
func NewWorker() Worker {
return Worker{JobQueue: make(chan Job)}
}
func (w Worker) Run(wq chan chan Job) {
go func() {
for {
select {
case job := <-w.JobQueue:
job.Do()
}
wq <- w.JobQueue //
}
}()
}
[workerpool.go]
package main
import "fmt"
待处理队列
type WorkerPool struct {
workerlen int // 任务处理者个数
JobQueue chan Job // 待处理的任务队列
WorkerQueue chan chan Job // 每个任务处理者的任务队列
}
func NewWorkerPool(workerlen int) *WorkerPool {
return &WorkerPool{
workerlen: workerlen,
JobQueue: make(chan Job),
WorkerQueue: make(chan chan Job, workerlen),
}
}
func (wp *WorkerPool) Run() {
//初始化worker
fmt.Println("初始化worker")
for i := 0; i < wp.workerlen; i++ {
worker := NewWorker()
worker.Run(wp.WorkerQueue)
// 调用worker.Run来处理任务
// 传入WorkerQueue的目的是为了WorkerQueue <- w.JobQueue,相当于在WorkerQueue里注册
}
// 循环获取可用的worker,往worker中写job
go func() {
for {
select {
case job := <-wp.JobQueue:
worker := <-wp.WorkerQueue
worker <- job
}
}
}()
}