个人介绍和该框架的开发背景指路:GO语言实践栏目介绍 - 知乎 (zhihu.com)

golang语言的一个重要特性就是对并发的支持:CSP思想是go语言对并发设计的核心。而刷脚本最重要的就是对并发的支持,如果有10000条数据,使用并行最起码可以使程序加速100倍以上!因此本章将会详细介绍go语言的并发以及在该脚本框架中使如何实现的。

Sync包

Sync包是许多语言都有的工具,在go语言中,除了Sync.once与Sync.WaitGroup以外,其他的模块都被建议使用在较为低级的并发环境,比如说多个协程对某些结构体的并发访问控制。而协程间的通信则更被建议使用channel进行交互。本章不对Sync包做过多介绍,挖个坑,后续对其和源码进行分析。


Channel

channel是什么

channel是CSP思想的核心体现,使用者可以将其理解为两个协程之间通信的管道。

和其他类型类似,channel的声明十分简单,这里以空接口的channel举例,一共有三种channel,双向、只读、只写,双向兼具读写功能。

很多人会在代码中只是用双向channel,但是笔者建议不要滥用双向channel,因为这涉及协程对channel的权限,使用单向channel可以让代码更加清晰。

channel的读写通常有两种模式:

直接读取模式

该模式可以通过ok判断reciveStream是否已经关闭,还有无数据

range模式

range 模式常常用来消费持续传入的数据

此外,channel也可以创建容量, 带缓冲队列的channel将极大影响channel的阻塞机制。

channel的状态查询:

当channel没有设置缓存队列时,如果发送方发送了数据但是接收方没有接受,发送协程将会阻塞。同样,如果接收方没有等到发送方的数据,接收方也会阻塞。类似于一种双向ready的模式。

而带缓冲channel则相当于有个缓存空间,只有发满了,或者读空了,对应的收发方才会阻塞。

此外,channel还可以主动关闭。

在写并发代码时,我们经常会遇到一种情况,代码不知道在哪里卡住了,不知道是哪个协程在发送信号给channel,还是从channel中读取数据阻塞了。这时候,我们可以根据下面的表格进行对应的查询和排查。

操作channel状态结果
Readnil阻塞
打开且非空输出值
打开且空阻塞
通道关闭<默认值>,false
只写通道编译错误
Writenil阻塞
打开且队列已满阻塞
打开且队列不满正常写入
通道关闭panic
只读通道编译错误
closenilpanic
打开且非空关闭channel,但是能读取,等到通道里没数据了,就会开始读默认值
打开且空正常关闭,读取默认值
通道已关闭panic
只读通道编译错误

该图选择Go语言并发之道,一本极好的go并发书:

channel妙用

使用channel我们可以设计出许多优秀的代码模式,这里仅介绍与该脚本框架相关的模式。

先介绍相关的语法与设计知识,想直接看全部代码解析的可以直接拉到下一部分

for-select

for-select 是重要的通道模式,通常的搭配是一个数据流,如dataStream,表示取到了数据你要做些什么,一个终止channel,表示提前结束这个协程。还有默认流,根据select-case的机制,如果case中的所有流都没有获取到数据,那么他就会堵塞,这时候default可以用来执行一些默认的操作。

pipeline

pipeline是处理流式数据的惯用设计方式,就像流水线一样工作保证每个协程,不会长期空闲。scripttool.go中的runsh采用的就是典型的流水线模式。


扇入

扇入就是将多个数据流复用或合并成一个流,典型的扇入代码如下所示:

multiplex协程将输入的流统一到multiplexStream中,并传出。利用waitgroup并发的进行扇入。

context

context是管理协程的绝佳工具,在golang语言开发中,经常会遇到一个问题,就是如何管理子协程的生命周期。context就有这个功能。详细的context介绍可以查询其他资料,这里仅说明本系统中使用的功能。仅需要注意这段代码中的ctx部分,从上游传来一个ctx,如果上游关闭了ctx,那么select就会接收到ctx.Done(),提前退出函数。利用ctx管理子协程的生命周期,是最为常见的用法之一

整段逻辑

通过前面的说明,这段代码看起来就容易许多了,rowDataStream负责传输文件的每行数据,rushDataRoutine开启了多个协程执行脚本,然后将每个协程的结果扇入给logDataStream,logDataRoutine读取该通道进行日志打印,done通道等待logdataStream执行完再退出主协程。这也是消费-订阅模型的一个基本模板


本期的主要内容就在这里,祝大家学有所得,下期将对超时和重试机制进行说明,干杯!