这个文章是作为学习笔记记录,学习应用地址:Go 系列教程 —— 23. 缓冲信道和工作池(Buffered Channels and Worker Pools)
自己书写的代码:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
/*
我们会使用缓冲信道来实现工作池。
我们工作池的任务是计算所输入数字的每一位的和。
例如,如果输入 234,结果会是 9(即 2 + 3 + 4)。向工作池输入的是一列伪随机数。
*/
/*
我们工作池的核心功能如下:
创建一个 Go 协程池,监听一个等待作业分配的输入型缓冲信道。
将作业添加到该输入型缓冲信道中。
作业完成后,再将结果写入一个输出型缓冲信道。
从输出型缓冲信道读取并打印结果。
*/
//首先需要两个结构体
//这个结构体表示存入随机数id和随机数
type Job struct {
Id int
randOnMo int
}
//表示每个随机数和随机数计算每一个数字的和的结果
type Result struct {
Job Job
SumOfDigits int
}
//用于写入作业的信道
var jobs = make(chan Job,10)
//用于输出作业的信道
var results = make(chan Result,10)
//表示有工作池的情况下 协程的运行与截止
func main() {
//工作协程(Worker Goroutine)会监听缓冲信道 jobs 里更新的作业。一旦工作协程完成了作业,其结果会写入缓冲信道 results。
startTime := time.Now() //当前时间
noOfJobs := 100
go allocate(noOfJobs) //开了一个协程 将所有需要的数据写入信道
//done := make(chan bool)
go result()
noOfWorker := 10
createWorkerPool(noOfWorker)
//<- done
endTime := time.Now()
diff := endTime.Sub(startTime)
fmt.Println("总得消耗掉的时间为 ",diff.Seconds()," 秒数")
}
/*
如下所示,digits 函数的任务实际上就是计算整数的每一位之和,最后返回该结果。
为了模拟出 digits 在计算过程中花费了一段时间,我们在函数内添加了两秒的休眠时间*/
func digits(Num int) (int) {
sum := 0;
no := Num
for no != 0 {
digit := no % 10
sum += digit
no /= 10
}
time.Sleep(2 * time.Second) //沉睡两秒
return sum
}
//作用是讲将数据计算写入结果
func Worker(wg *sync.WaitGroup) {
for job := range jobs{ //没一个协程都进行读取出jobs中的值
outPut := Result{job,digits(job.randOnMo)}
results <- outPut
}
wg.Done() //完成一个工作池减少一
}
//这个是作为go协程的工作池
//这个作用是为了能够创建工作吃,输入一个给点的数字 表示给了开了多少的协程。当每个协程都计算结束后,就关闭输出的信道
func createWorkerPool(noOfWorker int) {
var wg sync.WaitGroup
for i:=0; i< noOfWorker; i++ { //很快的开启noOfWorker个协程
wg.Add(1) //开启一个工作池加一
go Worker(&wg)
}
wg.Wait() //全部减去后再进行主协程的运行
close(results) //关闭输出信道
}
//现在我们已经有了工作池,我们继续编写一个函数,把作业分配给工作者。
func allocate(noOfJobs int) {
for i:=0 ; i< noOfJobs; i++ {
//生成随机数
var jobMo = rand.Intn(999)
var job = Job{i,jobMo}
jobs <- job
}
close(jobs)
}
//进行打印数据
func result() {
for result := range results {
fmt.Printf("Job的id是%d,Job的数字是%d,算出来的结果result是%d \n",result.Job.Id,result.Job.randOnMo,result.SumOfDigits)
}
//done <- true
}
理解内容:
1、工作流程是 首先开了一个协程写jobs中写上了100的数字作为值。
2、然后又开了一个协程作为result结果的读取
3、设置了工作数为10个(表示开了10个协程进行计算结果,且将计算的结果写入到result中,并且设置了工作池每次的操作,限制了必须等待所有协程读取写入到结果中的工作全部完成)
注意事项:
1、因为设置了10个协程进行结果的计算,所有每次打印的时候result的数据就是10个,当全部获取jobs的数据后,工作池也就结束了,然后关闭了结果输出的信道
2、写入信道数据后,必须要关闭信道
3、读取信道的数据,可以用range 或者用 for v,ok := jobs ,ok是否是正判断,不然会读取默认值。