并发程序的处理能力优势体现在哪里?
二、Go语言如何实现并发?
1packagemain
2
3import"fmt"
4import"time"
5
6funcgo_worker(name string) {
7fori := 0; i < 10; i++ {
8fmt.Println( "我是一个go协程, 我的名字是 ", name, "----")
9time.Sleep( 1* time.Second)
10}
11fmt.Println(name, " 执行完毕!")
12}
13
14funcmain{
15gogo_worker( "小黑") //创建一个goroutine协程去执行 go_worker("小黑")
16gogo_worker( "小白") //创建一个goroutine协程去执行 go_worker("小白")
17
18//防止main函数执行完毕,程序退出
19for{
20time.Sleep( 1* time.Second)
21}
22}
那么多个goroutine之前如何通信呢?
1packagemain
2
3import"fmt"
4
5funcworker(c chanint) {
6//从channel中去读数据
7num := <-c
8fmt.Println( "foo recv channel ", num)
9}
10
11funcmain{
12//创建一个channel
13c := make( chanint)
14
15goworker(c)
16
17//main协程 向一个channel中写数据
18c <- 1
19
20fmt.Println( "send 1 -> channel over")
21}
三、协程池的设计思路
为什么需要协程池?
虽然go语言在调度Goroutine已经优化的非常完成,并且Goroutine作为轻量级执行流程,也不需要CPU调度器的切换,我们一般在使用的时候,如果想处理一个分支流程,直接 go 一下即可。
但是,如果无休止的开辟Goroutine依然会出现高频率的调度Groutine,那么依然会浪费很多上下文切换的资源,导致做无用功。所以设计一个Goroutine池限制Goroutine的开辟个数在大型并发场景还是必要的。
四、快速实现并发协程通讯池
1packagemain
2
3import(
4"fmt"
5"time"
6)
7
8/* 有关Task任务相关定义及操作 */
9//定义任务Task类型,每一个任务Task都可以抽象成一个函数
10typeTask struct{
11f funcerror//一个无参的函数类型
12}
13
14//通过 NewTask来创建一个 Task
15funcNewTask(f funcerror) * Task{
16t := Task{
17f: f,
18}
19
20return&t
21}
22
23//执行Task任务的方法
24func(t *Task)Execute{
25t.f //调用任务所绑定的函数
26}
27
28/* 有关协程池的定义及操作 */
29//定义池类型
30typePool struct{
31//对外接收Task的入口
32EntryChannel chan*Task
33
34//协程池最大worker数量,限定Goroutine的个数
35worker_num int
36
37//协程池内部的任务就绪队列
38JobsChannel chan*Task
39}
40
41//创建一个协程池
42funcNewPool( capint) * Pool{
43p := Pool{
44EntryChannel: make( chan*Task),
45worker_num: cap,
46JobsChannel: make( chan*Task),
47}
48
49return&p
50}
51
52//协程池创建一个worker并且开始工作
53func(p *Pool)worker(work_ID int) {
54//worker不断的从JobsChannel内部任务队列中拿任务
55fortask := rangep.JobsChannel {
56//如果拿到任务,则执行task任务
57task.Execute
58fmt.Println( "worker ID ", work_ID, " 执行完毕任务")
59}
60}
61
62//让协程池Pool开始工作
63func(p *Pool)Run{
64//1,首先根据协程池的worker数量限定,开启固定数量的Worker,
65// 每一个Worker用一个Goroutine承载
66fori := 0; i < p.worker_num; i++ {
67gop.worker(i)
68}
69
70//2, 从EntryChannel协程池入口取外界传递过来的任务
71// 并且将任务送进JobsChannel中
72fortask := rangep.EntryChannel {
73p.JobsChannel <- task
74}
75
76//3, 执行完毕需要关闭JobsChannel
77close(p.JobsChannel)
78
79//4, 执行完毕需要关闭EntryChannel
80close(p.EntryChannel)
81}
82
83//主函数
84funcmain{
85//创建一个Task
86t := NewTask( funcerror{
87fmt.Println(time.Now)
88returnnil
89})
90
91//创建一个协程池,最大开启3个协程worker
92p := NewPool( 3)
93
94//开一个协程 不断的向 Pool 输送打印一条时间的task任务
95gofunc{
96for{
97p.EntryChannel <- t
98}
99}
100
101//启动协程池p
102p.Run
103
104}