服务器编程使用最多的就是通过线程池提升服务的并发执行能力,在go语言中,一样可以轻松的构建固定数目的goroutine作为线程池,下面通过计算多个整数的和来说明这种并发范式。
设计思路:
除了主要的main goroutine ,还需开启以下几类goroutine
1,初始化任务的goroutine
2,分发任务的goroutine
3,等到所有work结束,然后关闭所有通道的goroutine
main主要负责拉起以上的goroutine 冰火取结果
程序还需要三个通道
1,传递task任务的通道
2,传递task结果的通道
3 ,接收workder处理完任务后所发送通知的通道
具体代码如下
package go_worker import ( "fmt" ) //定义工作数量 const ( WORKS=5 ) //定义工作任务结构体,可根据需求改变 type task struct { begin int end int result chan<- int } //定义执行任务的方法,可根据需求更改 func (t *task) do(){ sum:=0 for i:=t.begin;i<=t.end;i++{ sum++ } t.result<-sum } //入口函数 func main(){ works:=WORKS //定义工作通道 taskchan:=make(chan task,10) //定义结果通道 resultchan:=make(chan int,10) //work工作信号通道 done:=make(chan struct{},10) //初始化task的goroutine go initTask(taskchan,resultchan,100); //分发任务到协程池 distributeTask(taskchan,works,done) //获取goroutine处理完成任务通知,并关闭通道 go closeResult(done,resultchan,works) //通过结果通道,获取结果并汇总 sum:=processResult(resultchan) fmt.Println("sum=",sum) } //初始化task chan func initTask(taskchan chan<-task,r chan int ,p int){ qu:=p/10 mod:=p%10 high:=qu*10; for j:=0;j<qu;j++{ b:=10*j+1 e:=10*(j+1) task:=task{ begin:b, end:e, result:r, } taskchan<-task } if mod!=0{ task:=task{ begin:high+1, end:p, result:r, } taskchan<-task } close(taskchan) } //读取taskchan 并分发到worker goRoutine处理,总数量为workers func distributeTask(taskchan<-chan task,workers int ,done chan struct{}){ for i:=0;i<workers;i++{ go processTask(taskchan,done) } } //工作goroutine处理的具体内容,并将处理的结果发送到结果chan func processTask(taskchan <-chan task,done chan struct{}){ for t:=range taskchan{ t.do() } done<- struct{}{} } //通过done channel同步等待所有工作goroutine的结束,然后关闭结果chan func closeResult(done chan struct{},resultchan chan int ,workers int ){ for i:=0;i<workers;i++{ <-done } close(done) close(resultchan) } //读取结果通道汇聚结果 func processResult(resultchan chan int )int{ sum:=0 for r:=range resultchan{ sum+=r } return sum }
ok ,至此,程序结束,可将task和task.do() 替换成自己的已有逻辑执行