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语言在语 ...
随机推荐
- 测试 windows 发布日志
<script>alert("hellow world")</script>
- Kendo UI for jQuery使用教程:支持Web浏览器
[Kendo UI for jQuery最新试用版下载] Kendo UI目前最新提供Kendo UI for jQuery.Kendo UI for Angular.Kendo UI Support ...
- 别再误解MySQL和「幻读」了
The so-called phantom problem occurs within a transaction when the same query produces different set ...
- redis优雅的批量删除key
redis优雅的批量删除key 近期在处理redis的故障中,发现需要删除大量的历史数据(也是bigkeys),好在符合正则表达式.要不然就很痛苦,这也体现了在设计key的时候遵循规范带来的维护好处之 ...
- 读取xml文件中的配置参数实例_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 paras.xml文件 <?xml version="1.0" encoding=" ...
- 利用poi操作word文档
关键字:POI JAVA 批注 总页数 总字符数 一:认识POI Apache POI是一个开源的利用Java读写Excel.WORD等微软OLE2组件文档的项目.最新的3.5版本有很多改进,加入了对 ...
- python中的时间模块
废话不多说,看代码 import datetime,time import calendar #时间戳 t1 = time.time() print('当前时间戳是{}'.format(t1)) #格 ...
- Cassandra 数据一致性
基本概念 一致性: 在分布式系统中的所有数据备份,在同一时刻是否同样的值 QUORUM: 是一个可以计算的数字,对数据一致性起重要作用 Node: 主要用来存储数据 Data Center: 数据中心 ...
- 箱排序(Bin Sort)
1.基本思想 排序过程无须比较关键字,而是通过"分配"和"收集"过程来实现排序.它们的时间复杂度可达到线性阶:O(n). 箱排序也称桶排序(Bucket Sor ...
- ZOJ 2301 离散化
题目链接: 题意是说,有从 1 开始递增依次编号的很多球,开始他们都是黑色的,现在依次给出 n 个操作(ai,bi,ci),每个操作都是把编号 ai 到 bi 区间内的所有球涂成 ci 表示的颜色(黑 ...