Go 语言中的 channel 学习
主要学习 Go 语言中 channel 数据结构使用,以及工作过程中的避坑。文章中的代码主要参考极客时间 go 并发编程,如有需要查看其详细内容,请前去购买!
channel 使用方向上的避坑
虽然 Go 的开发者极力推荐使用 channel。但是通过大家的工程化道路上的探索, channel 并不是处理并发问题的普适性的使用方法,有时候使用传统的并发原语更简单,而且不容易出错。
所以在使用并发原语时候,一般遵循以下几种设置方式:
1、共享资源的并发访问使用传统并发原语
2、复杂的任务编排和消息传递使用 channel
3、消息通知机制使用 channel,除非只想 signal 一个 goroutine,才使用 Cond
4、简单等待所有任务的完成用 WaitGroup,也有 channel 的推崇者用 channel,都可以
5、需要和 select 语句结合,使用 channel
6、需要和超时配合时,使用 channel 和 context
channel 具体使用的方式
1、动态处理不定数量的 channel ,使用 reflect.Select 函数,将 channel 当成参数传入,具体案例代码如下:
1 |
|
上述代码先使用 createCases 函数分别为每个 channel 生成了 recv case 和 send case,并返回一个 reflect.SelectCase 数组。
然后,通过一个循环 10 次的 for 循环执行 reflect.Select 从 cases 中伪随机的选择一个 case 执行。
第一次肯定是 send case,因为此时 channel 还没有元素,recv 还不可用。等 channel 中有了数据以后,recv case 就可以被选择了。这就可以处理不定数量的 channel 。
2、经典的消息传递案例
有 4 个 goroutine,编号为 1、2、3、4。每秒钟会有一个 goroutine 打印出它自己的编号,要求你编写程序,让输出的编号总是按照 1、2、3、4、1、2、3、4……这个顺序打印出来。
1 |
|
首先,我们定义一个令牌类型 Token,其结构为空的 struct,一般都是使用空结构体进行消息的通知!
接着定义一个创建 worker 的方法,这个方法会从它自己的 chan 中读取令牌。哪个 goroutine 取得了令牌,就可以打印出自己编号。
因为需要每秒打印一次数据,所以,我们让它休眠 1 秒后,再把令牌交给它的下家。接着,在第 16 行启动每个 worker 的 goroutine,并在第 20 行将令牌先交给第一个 worker
这样,就会保证程序的运行是 1、2、3、4 的顺序输出。