Go 语言核心 36 讲
郝林
《Go 并发编程实战》作者,前轻松筹大数据负责人
79610 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 55 讲
Go 语言核心 36 讲
15
15
1.0x
00:00/00:00
登录|注册

11 | 通道的高级玩法

退出外层的for语句
屏蔽已关闭的通道分支
分支选择规则
与通道联用
Notifier接口类型声明
SendInt函数
约束其他代码的行为
思考题
select语句
函数类型中的约束
函数声明中的约束
应用价值
接收通道
发送通道
单向通道
通道的高级玩法

该思维导图由 AI 生成,仅供参考

我们已经讨论过了通道的基本操作以及背后的规则。今天,我再来讲讲通道的高级玩法。
首先来说说单向通道。我们在说“通道”的时候指的都是双向通道,即:既可以发也可以收的通道。
所谓单向通道就是,只能发不能收,或者只能收不能发的通道。一个通道是双向的,还是单向的是由它的类型字面量体现的。
还记得我们在上篇文章中说过的接收操作符<-吗?如果我们把它用在通道的类型字面量中,那么它代表的就不是“发送”或“接收”的动作了,而是表示通道的方向。
比如:
var uselessChan = make(chan<- int, 1)
我声明并初始化了一个名叫uselessChan的变量。这个变量的类型是chan<- int,容量是1
请注意紧挨在关键字chan右边的那个<-这表示了这个通道是单向的,并且只能发而不能收。
类似的,如果这个操作符紧挨在chan的左边,那么就说明该通道只能收不能发。所以,前者可以被简称为发送通道,后者可以被简称为接收通道。
注意,与发送操作和接收操作对应,这里的“发”和“收”都是站在操作通道的代码的角度上说的。
从上述变量的名字上你也能猜到,这样的通道是没用的。通道就是为了传递数据而存在的,声明一个只有一端(发送端或者接收端)能用的通道没有任何意义。那么,单向通道的用途究竟在哪儿呢?
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

通道高级玩法及select语句的联用是本文的重点。文章介绍了单向通道的概念和应用,以及使用`<-`操作符表示通道方向的方式。单向通道可约束函数声明和接口类型声明,限制代码行为。此外,还探讨了在函数声明结果列表和函数类型中使用单向通道的约束作用。另外,文章详细介绍了`select`语句与通道的联用方式,以及分支选择规则。`select`语句的分支选择规则包括表达式求值顺序、阻塞状态判断、分支选择条件满足时的执行顺序等。总的来说,本文通过介绍单向通道的概念和应用,以及`select`语句与通道的联用方式,帮助读者深入理解通道的高级玩法。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Go 语言核心 36 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(58)

  • 最新
  • 精选
  • 左氧佛沙星人
    老师好,demo25中的这段代码我没看懂,不是这个匹配上了吗?为啥没有执行呢?我理解应该打印The second candidate case is selected.。。。。 ``` case getChan(1) <- getNumber(1): ``` 能指点一下吗?

    作者回复: 因为 make(chan int) 初始化的是不带缓冲的通道。非缓冲通道只有在收发双方都就绪的情况下才能传递元素值,否则就阻塞。

    2019-03-25
    4
    35
  • 到不了的塔
    郝老师,请问第一题的答案是啥,不知道怎么屏蔽分支呢

    作者回复: 设置为nil就可以了。

    2018-10-24
    2
    20
  • 笨笨
    谢谢赫老师今日分享,回答问题如下 1.对于select中被close的channel判断其第二个boolean参数,如果是false则被关闭,那么赋值此channel为nil,那么每次到这个nil的channel就会阻塞,select会忽略阻塞的通道,如果再搭配上default就一定能保证不会被阻塞了。 2.通过定义标签,配合goto或者break能实现在同一个函数内任意跳转,故可以跳出多层嵌套的循环。

    作者回复: 你的问题是什么?

    2018-09-05
    19
  • zhaopan
    老师好: 仅当select语句中的所有case表达式都被求值完毕后,它才会开始选择候选分支。 当接收通道操作有多个满足条件时, 这里的所有case表达式都被求值完毕, 应该怎么理解? 是多个case表达式都能接收到通道的数据么? 如果都接收了, 随机选择一个分支去处理接收的通道数据. 那其他满足条件的case分支怎么执行到了? 如果是外层加for循环, 重新select语句, 那上一次select的操作其他满足条件未被选择的case还能收到上一次的数据么? 这里的原理是什么呢?

    作者回复: 这里只会检查一下接收操作或发送操作是否可以进行(是否不会被阻塞)。有兴趣的话可以看一下 runtime/select.go 中的 selectgo 函数的源码。

    2019-02-19
    2
    11
  • hunknownz
    当第二个boolean参数为false的时候,在相应的case中设置chan为nil零值,再次case求值的时候会遭遇阻塞,会屏蔽该case。

    作者回复: 是的。

    2018-11-05
    11
  • Tron
    请教老师一个问题, 如果我用context 取消一个正在执行的下载任务,形如: select { case i := <- jobs: downloadBigBigFile() case ctx <-Done return } 当 父进程发出cancel 指令后, 能够取消downloadBigBigFile()里面运行的任务吗?

    作者回复: 首先修正一点,这与进程无关,与 goroutine 有关,而且没有父子关系。 正题回答:不能。因为程序流程已经走到 downloadBigBigFile() 这里了,不可能在没有循环或跳转的情况下再往回走。 看起来你应该把 ctx 放入 downloadBigBigFile 函数,然后在这个函数里做判断。

    2019-09-04
    8
  • Flo
    对zhaopan的问题中老师的回复存在疑惑,老师回复如下:“作者回复: 这里只会检查一下接收操作或发送操作是否可以进行(是否不会被阻塞)。有兴趣的话可以看一下 runtime/select.go 中的 selectgo 函数的源码。” -----这里是不是表示,对于那些符合条件但没有执行到的case,之前判断的时候是不是并没有从chan中取出数据?

    作者回复: 不好意思,问问题的人太多了,你问的时候最好带上比较完整的上下文。我下面按我目前对你问题的理解回答你吧。 select 语句对某个 case 中的通道接收表达式的实际执行需要两个前提条件: 1. 接收操作不会被阻塞。 2. 当前 case 被选中。 对于 case 中的通道发送表达式来说也是类似。因此,我们完全不用担心那些未被选中的通道操作会突然执行。

    2019-04-23
    5
  • 癫狂的小兵
    请问当select语句发现多个分支满足条件时随机选择一个分支执行 那怎样让其他满足条件的分支执行呢? for 循环 等待下一次循环时再执行?

    作者回复: 放在for循环里每次也是随机的,不过可以用for循环,或者再次执行select语句。

    2018-09-05
    5
  • 长杰
    函数定义,有的用首字母大写的命名规则,有的用驼峰命名规则,老师能介绍一下go语言编程的规范介绍吗?

    作者回复: 你可以看看我在前面的(程序实体相关的)文章中讲的。程序实体的名称如果首字母大写那么就说明是其访问权限是公开的,否则就是包级私有的。

    2019-01-13
    4
  • Neo
    请问老师: select 分支选择规则中第5个:"如果select语句发现同时有多个候选分支满足选择条件,那么它就会用一种伪随机算法在这些分支中选择一个执行" 随机选一个执行 那我们是不是就不能确定程序会执行哪一条与语句了?

    作者回复: 这种情况下是这样。

    2018-09-12
    4
收起评论
显示
设置
留言
58
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部