文本描述
2020/11/15 14 | Channel:透过代码看典型的应用模式-极客时间 下载APP 14 | Channel:透过代码看典型的应用模式 2020-11-11 晁岳攀 Go 并发编程实战课 进入课程 讲述:安晓辉 时长 20:59 大小 19.23M 你好,我是鸟窝。 前一讲,我介绍了 Channel 的基础知识,并且总结了几种应用场景。这一讲,我将通过实 例的方式,带你逐个学习 Channel 解决这些问题的方法,帮你巩固和完全掌握它的用法。 在开始上课之前,我先补充一个知识点:通过反射的方式执行 select 语句,在处理很多的 case clause,尤其是不定长的 case clause 的时候,非常有用。而且,在后面介绍任务编 排的实现时,我也会采用这种方法,所以,我先带你具体学习下 Channel 的反射用法。 使用反射操作 Channel time.geekbang.org/column/article/306614 1/24 2020/11/15 14 | Channel:透过代码看典型的应用模式-极客时间 select 语句可以处理 chan 的 send 和 recv,send 和 recv 都可以作为 case clause。如 果我们同时处理两个 chan,就可以写成下面的样子: 复制代码 1 select { 2 case v := <-ch1: 3 fmt.Println(v) 4 case v := <-ch2: 5 fmt.Println(v) 6 } 如果需要处理三个 chan,你就可以再添加一个 case clause,用它来处理第三个 chan。可 是,如果要处理 100 个 chan 呢?一万个 chan 呢? 或者是,chan 的数量在编译的时候是不定的,在运行的时候需要处理一个 slice of chan, 这个时候,也没有办法在编译前写成字面意义的 select。那该怎么办? 这个时候,就要“祭”出我们的反射大法了。 通过 reflect.Select 函数,你可以将一组运行时的 case clause 传入,当作参数执行。Go 的 select 是伪随机的,它可以在执行的 case 中随机选择一个 case,并把选择的这个 case 的索引(chosen)返回,如果没有可用的 case 返回,会返回一个 bool 类型的返回值, 这个返回值用来表示是否有 case 成功被选择。如果是 recv case,还会返回接收的元素。 Select 的方法签名如下: 复制代码 1 func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) 下面,我来借助一个例子,来演示一下,动态处理两个 chan 的情形。因为这样的方式可 以动态处理 case 数据,所以,你可以传入几百几千几万的 chan,这就解决了不能动态处 理 n 个 chan 的问题。 首先,createCases 函数分别为每个 chan 生成了 recv case 和 send case,并返回一个 reflect.SelectCase 数组。 time.geekbang.org/column/article/306614 2/24 2020/11/15 14 | Channel:透过代码看典型的应用模式-极客时间 然后,通过一个循环 10 次的 for 循环执行 reflect.Select,这个方法会从 cases 中选择一 个 case 执行。第一次肯定是 send ca