Golang 协程与缓冲信道、工作池的理解

这个文章是作为学习笔记记录,学习应用地址: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是否是正判断,不然会读取默认值。

你可能感兴趣的:(golang)