Nil Channels Always Block(Go语言中空管道总是阻塞)
译自:https://www.godesignpatterns.com/2014/05/nil-channels-always-block.html
原作者:Alex Lockwood
在本篇文章中,我们将讨论 nil channel 在 Go 中的使用。nil channel 无论是接收还是发送都会永久阻塞:
// Create an uninitialized (nil) channel.
var ch chan struct{} // Receiving on a nil channel blocks forever.
<-ch // Sending on a nil channel will also block forever.
ch <- struct{}{}
nil channel 看上去似乎没有什么用,甚至曾经在你的项目中引起 bug(例如忘记在使用 channels 前,用 make 初始化)。但是,可以通过几种巧妙的方式利用此属性,特别是当你需要在 select 语句中动态禁用一个 case:
if disableSelectCase {
ch1 = nil
} else {
ch1 = nonNilChan
}
select {
case <-ch1:
// This case will only be considered if ch1 is not nil.
// 这个 case 直到 ch1 不是 nil 时才会被考虑
case <-ch2:
// This case will always be considered (assuming ch2 is non-nil).
}
上面的 code 阐明了这样一个特征,当 select 语句中的一个case 是 nil channel 时,它将会选择性忽略。如果 boolean 类型的 disableSelectCase 为 true ,此时会将 nil 赋值给 ch1,从而阻止 ch1 channel 被 select 语句考虑。
这种特性也被用来防止空循环,比如当你需要等待多个 channels 关闭时:
// WARNING! Spin loop might occur!
var isClosed1, isClosed2 bool
for !isClosed1 || !isClosed2 {
select {
case _, ok := <-ch1:
if !ok {
isClosed1 = true
}
case _, ok := <-ch2:
if !ok {
isClosed2 = true
}
}
}
如果上面的代码中两个 channel 有一个被关闭,将会在你的项目中引起一个小 bug。因为被关闭的 channel 永远不会阻塞,如果 ch1 被关闭,ch1 在随后的循环迭代中将总是准备被接收。作为结果,程序将陷入死循环,还有就是 case <- ch2 也许再也没有机会被执行。
为了解决这个问题,我们可以利用 nil channel 总是阻塞的特性:
// Safely disable channels after they are closed.
for ch1 != nil || ch2 != nil {
select {
case _, ok := <-ch1:
if !ok {
ch1 = nil
}
case _, ok := <-ch2:
if !ok {
ch2 = nil
}
}
}
Nil Channels Always Block(Go语言中空管道总是阻塞)的更多相关文章
- Go语言的管道Channel用法
本文实例讲述了Go语言的管道Channel用法.分享给大家供大家参考.具体分析如下: channel 是有类型的管道,可以用 channel 操作符 <- 对其发送或者接收值. ch <- ...
- go语言mongdb管道使用
原始json: { "listsn": "", "code": "fwq_add", "detail" ...
- C语言与管道
int main() { int s; int n; float avg; scanf("%d,%d",&s,&n); //特别注意的地方 // scanf(&qu ...
- Go语言 channel 管道 阻塞 死锁 经典问题
建议阅读:14.2协程间的信道 问题:为什么代码1会报死锁的错误,而代码2不会报错? 代码1: package main import ( "fmt" ) func main() ...
- Linux有名管道的 阻塞VS非阻塞 读写
参考文章: 关于有名管道open时阻塞的问题 Linux有名管道(FIFO)的阻塞和非阻塞读写 挖坑,日后填
- 029_go语言中的非阻塞通道
代码演示 package main import "fmt" func main() { messages := make(chan string) signals := make ...
- C语言键盘按键无阻塞侦测:kbhit()
http://www.360doc.com/content/12/0414/09/1317564_203474440.shtml kbhit in c kbhit in c: kbhit functi ...
- Golang并发编程——goroutine、channel、sync
并发与并行 并发和并行是有区别的,并发不等于并行. 并发 两个或多个事件在同一时间不同时间间隔发生.对应在Go中,就是指多个 goroutine 在单个CPU上的交替运行. 并行 两个或者多个事件在同 ...
- Go语言中的管道(Channel)总结
管道(Channel)是Go语言中比较重要的部分,经常在Go中的并发中使用.今天尝试对Go语言的管道来做以下总结.总结的形式采用问答式的方法,让答案更有目的性. Q1.管道是什么? 管道是Go语言在语 ...
随机推荐
- Linux之RedHat7如何更换yum源
目前,我们常见的系统大概就是Windows.Linux和Mac OS了.Windows系统应该是大部分人最早开始接触的系统,毕竟Windows系统使用起来相当方便,只需要点点鼠标,外加会简单的打字,一 ...
- 安装与学习laravel
安装 composer cd /var/www/html curl -sS https://getcomposer.org/installer | php mv composer.phar /usr/ ...
- 关闭mmu和cache
处理器内部寄存器,访问速度最快,但是数量少 TCM:紧耦合存储器(Cache.主存储器) 辅助存储器(Flash.SD等) Cache是一种容量小但是存取速度非常快的存储器 它保存最近用到的存储器中的 ...
- 四、Signalr手持令牌验证
一.JWT 服务端在respose中设置好cookie,浏览器发请求都会自动带上,不需要做额外设置 但是如果客户端是非浏览器,或者要兼容多种客户端,这个方法就不行了 Js端 @{ Layout = n ...
- Spring Framework Part3 IoC and Dynamic Proxy
spring serious of blog edit by 马士兵教育 Maven方式创建Spring工程 工程创建 1.新建项目 选择Maven Project 2.勾选 Create a sim ...
- 使用kong-dashboard
具体命令行操作只需按照官网一步一步来即可(https://docs.konghq.com/1.4.x/getting-started/configuring-a-service/),这里介绍图形化操作 ...
- UIWebView半透明设置
在项目中有时候需要弹出活动弹框,由于原生的样式会固定,所以考虑h5显示,这就需要webView的背景色半透明,如图: 让 UIWebView 背景透明需要以下设置 webView.backgroun ...
- 【洛谷P4677】山区建小学
题目大意:给定一个长度为 N 的序列,现选出 M 个点组成一个集合,求这 N 个点到这个集合的最近距离的和是多少. 题解: 状态设计为 dp[i][j] 表示前 i 个点中选出 j 个点的最近距离和是 ...
- Markdown小结
Markdown标题 以# (#号加空格)开头的行会被视为标题,根据#的数量分为一到六级标题 # 一级标题 ## 二级标题 … ###### 六级标题 Markdown 水平线 一行由三个以上连续的减 ...
- [51nod 1830] 路径交
问题描述 给定一棵n个点的树,以及m条路径,每次询问第L条到第R条路径的交集部分的长度(如果一条边同时出现在2条路径上,那么它属于路径的交集). 输入格式 第一行一个数n(n<=500,000) ...