译自: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语言中空管道总是阻塞)的更多相关文章

  1. Go语言的管道Channel用法

    本文实例讲述了Go语言的管道Channel用法.分享给大家供大家参考.具体分析如下: channel 是有类型的管道,可以用 channel 操作符 <- 对其发送或者接收值. ch <- ...

  2. go语言mongdb管道使用

    原始json: { "listsn": "", "code": "fwq_add", "detail" ...

  3. C语言与管道

    int main() { int s; int n; float avg; scanf("%d,%d",&s,&n); //特别注意的地方 // scanf(&qu ...

  4. Go语言 channel 管道 阻塞 死锁 经典问题

    建议阅读:14.2协程间的信道 问题:为什么代码1会报死锁的错误,而代码2不会报错? 代码1: package main import ( "fmt" ) func main() ...

  5. Linux有名管道的 阻塞VS非阻塞 读写

    参考文章: 关于有名管道open时阻塞的问题 Linux有名管道(FIFO)的阻塞和非阻塞读写 挖坑,日后填

  6. 029_go语言中的非阻塞通道

    代码演示 package main import "fmt" func main() { messages := make(chan string) signals := make ...

  7. C语言键盘按键无阻塞侦测:kbhit()

    http://www.360doc.com/content/12/0414/09/1317564_203474440.shtml kbhit in c kbhit in c: kbhit functi ...

  8. Golang并发编程——goroutine、channel、sync

    并发与并行 并发和并行是有区别的,并发不等于并行. 并发 两个或多个事件在同一时间不同时间间隔发生.对应在Go中,就是指多个 goroutine 在单个CPU上的交替运行. 并行 两个或者多个事件在同 ...

  9. Go语言中的管道(Channel)总结

    管道(Channel)是Go语言中比较重要的部分,经常在Go中的并发中使用.今天尝试对Go语言的管道来做以下总结.总结的形式采用问答式的方法,让答案更有目的性. Q1.管道是什么? 管道是Go语言在语 ...

随机推荐

  1. Source Insight 中调用Notepad++

    options>custom commands 指令为 "E:\Program Files (x86)\Notepad++\notepad++.exe" %f 其中%f表示S ...

  2. java.lang.Integer 类(JDK1.7)

    1.Integer 和int 的区别 ①.Integer 是 int 包装类,int 是八大基本数据类型之一(byte,char,short,int,long,float,double,boolean ...

  3. Codeforces 990 调和级数路灯贪心暴力 DFS生成树两子树差调水 GCD树连通块暴力

    A 水题 /*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) using namespace ...

  4. Django学习系列7:使用模板解决“不测试常量”规则,使用模板重构

    之前写的lists/tests.py中的单元测试,要查找特定的HTML字符串,但这不是测试HTML的高效方法. 单元测试规则之一“不测试常量”,编写断言检测HTML字符串中是否有制定的字符串序列,不是 ...

  5. vue打包多页报错webpackJsonp is not defined

    找到build→webpack.prod.conf.js→找到HtmlWebpackPlugin插件,添加如下配置即可 chunks: ['manifest', 'vendor', 'app']

  6. Quantitative Strategies for Achieving Alpha (三)

    chapter 4: Profitability Profitability measures we tested include return on invested capital, return ...

  7. CF1242C. Sum Balance

    题目描述 k组数,每组ni个,数互不相同 把每组数中的一个移到其他组(或者不移动),使得最终每组数的个数不变且总和相等 k<=15,ni<=5000 题解 最终的移动关系一定为若干个环 枚 ...

  8. DevOps之持续集成Jenkins+Gitlab

    一.什么是DevOps DevOps(英文Development(开发)和Operations(技术运营)的组合)是一组过程.方法与系统的统称,DevOps是一组最佳实践强调(开发.运维.测试)在应用 ...

  9. ETL工具之kittle使用案例整理

    主花了一下午时间,收集全网,学习了下kittle,觉得该大v写的不错,特意整理给大家!学会这几个案例kittle基本就没问题了. 1.kettle案例一抽取gz格式文本内容保存到mongodb  ht ...

  10. teradata安装

    一,下载 步骤1 - 从链接下载所需的VM版本,http://downloads.teradata.com/download/database/teradata-express-for-vmware- ...