并发程序的处理能力优势体现在哪里?

二、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}