译自: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. centos7 安装部署zabbix客户端

    1.下载安装zabbix-agent: # rpm -ivh http://repo.zabbix.com/zabbix/3.4/rhel/7/x86_64/zabbix-release-3.4-2. ...

  2. Linux sed神器

    sed -i -c -e '/^#/d'去掉注释行 sed -i -c -e '/^$/d'去掉空行 sed -i -c -e '/^$/d;/^#/'同时去掉空行和注释行 sed -i 's/^/H ...

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

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

  4. 问题:关于2.3 jmu-Java-02基本语法-03-身份证排序 (9 分)

    输出未能排序     import java.util.Scanner;     import java.util.Arrays;     public class Main {         pu ...

  5. ZROI 19.08.10模拟赛

    传送门 写在前面:为了保护正睿题目版权,这里不放题面,只写题解. A \(20pts:\) 枚举操作序列然后暴力跑,复杂度\(O(6^n)\). \([50,80]pts:\) 枚举改成dfs,每层操 ...

  6. mysql安装配置和启动

    MySQL数据库安装配置和启动   1,下载MySQL 打开MySQL的官网www.mysql.com,发现有一个DOWNLOADS 点击它,进入到MySQL的下载页面,在页面的底部有一个MySQL ...

  7. python类库32[多进程通信Queue+Pipe+Value+Array]

    多进程通信 queue和pipe的区别: pipe用来在两个进程间通信.queue用来在多个进程间实现通信. 此两种方法为所有系统多进程通信的基本方法,几乎所有的语言都支持此两种方法. 1)Queue ...

  8. 百度地图api的简单应用(二):轻量级路径规划

    同上篇的原理,我们还是输入url,返回json文件. 而由图可见,路径规划返回的json文件内容可能会很多.杂: 因此后续的处理与上篇略有不同. import json import requests ...

  9. Levenberg-Marquardt优化和zipf分布

    最近审论文和看报告中遇到LM优化和齐普夫分布,于是查了一下. LM方法是高斯牛顿迭代方法的改进,下面分别是高斯牛顿.齐普夫方法的公式: Δ=−(JfTJf)−1JfTf,Δ=−(JfTJf+λI)−1 ...

  10. 伸展树splay之求区间极值

    前言 这篇博客是根据我在打这道题的时候遇到的问题,来打的,有些细节可能考虑不到. 题目 在N(1<=N<=100000)个数A1-An组成的序列上进行M(1<=M<=10000 ...