go语言生态学习

第五天:go多协程开发学习



前言

go以协程实现了并发操作,协程又叫goroutine,是一个比线程更小的运行单位,只在用户态下运行,通信方式为channel。go项目在1.11版本之后均开始使用go mod方式管理项目模块和不同模块之间的调用。


一、协程goroutine

1.协程运行模型


如图为协程的运行模型,一个内核态线程运行占用一个处理器,当存在线程运行时,处理器忙碌。协程运行在用户态,通过协程调度处理器来决定协程运行在局部队列还是全局队列,局部队列的协程按照抢占式策略运行在一个内核态线程上,全局队列的协程在有处理器空闲或者局部协程队列有空闲时加入运行队列。因而协程和线程之间是M:N模型,一个协程可以同时运行在多个线程上,一个线程可以绑定多个协程来运行,他们之间通过一个调度处理器来形成绑定运行的关系。

2.协程使用方法

首先明确主协程和子协程的概念,只有main函数启动的协程为主协程,所有go关键字启动运行的函数为子协程,当主协程退出运行时,所有子协程无论执行完毕与否均立刻退出运行。
在一个调用函数前加go表示启动一个子协程:

go func(){}()
二、协程通信channel

1.channel初始化

channel初始化分为有缓存和无缓冲模式,其区别在于有缓存channel始化长度大于0,无缓冲channel初始化长度等于0。有缓存和无缓冲的channel使用方法也不相同。
无缓存channel初始化方法:

c := make(chan dataType) // dataType为channel运输的数据类型
c := make(chan dataType, 0) // 与一种初始化方法相同

有缓存channel初始化方法

c := make(chan dataType, len) // dataType为channel运输的数据类型,len为初始化长度

2.channel使用方法

数据写入channel:

c <- data

从channel读出数据:

<-c // 数据读出但是不使用直接丢弃,一般打印时使用
data <-c // 读出数据
data, ok <-c // 读出数据并作判断,ok = true表示channel有数据可读, ok = false表示channel关闭,且无数据可读

注意一点,当channel关闭时,不可写入数据,但是可以读出数据。

3.有无缓存channel同步异步问题

无缓存的channel同步过程分两种情况讨论,一种是数据读取方指令先运行到读channel,另一种是数据输入方指令先运行到写入channel,因为无缓存条件下,数据没法保存,所以无论上述哪一种情况均需要等待对方落位,然后交换数据完成后后,双方继续并发运行,这里看起来就是一个同步过程。

有缓存的channel同步过程同样分两种情况讨论,一种是数据读取方先运行到读channel,因为没有数据可读,同样需要等待输入方输入数据,这是同步过程,另一种情况是数据输入方先指令先运行到写入channel,则当数据输入完成,继续执行后续指令,无需等待,数据读取方读取到channel有值时自动读取,这是一个异步过程。