Go channel系列

双层通道的解释见Go的双层通道

以下是一个双层通道的使用示例。注意下面的示例中使用了"信号通道"(Signal channel),但这里的信号通道是多余的,仅仅只是为了介绍。

信号通道不用来传递数据,而是用来传递消息,用来产生可读、可写的事件,以便让select选中某个分支。产生消息事件的方式有多种,比如直接关闭通道、发送false/true布尔值等等

package main

import (
"fmt"
"time"
) func main() {
// 定义双层通道cc
cc := make(chan chan int)
times := 5
for i := 1; i < times+1; i++ {
// 定义信号通道f
f := make(chan bool) // 每次循环都在双层通道cc中生成内层通道c
// 并通过信号通道f来终止f1()
go f1(cc, f) // 从双层通道cc中取出内层通道ch
// 并向ch通道发送数据
ch := <-cc
ch <- i // 从ch中取出数据
for sum := range ch {
fmt.Printf("Sum(%d)=%d\n", i, sum)
}
// 每个循环睡眠一秒钟
time.Sleep(time.Second)
// 每次循环都关闭信号通道f
close(f)
}
} // 双层通道cc用来生成内层通道c
// 并使用信号通道f来终止函数f1()
func f1(cc chan chan int, f chan bool) {
c := make(chan int)
cc <- c
defer close(c)
sum := 0
select {
// 从内层通道中取出数据,计算和,然后发回内层通道
case x := <-c:
for i := 0; i <= x; i++ {
sum = sum + i
}
// goroutine将阻塞在此,直到数据被读走
c <- sum
// 信号通道f可读时,结束f1()的运行
// 但因为select没有在for中,该case分支用不上
case <-f:
return
}
}

上面的示例中,函数f1()两个参数,一个是双层通道cc,一个是信号通道f。f1()中首先生成了一个通道c,并发送给了双层通道cc,使得main()中可以从cc中取得这个内层通道c,并向其发送数据。

回到f1()中,select最初会被阻塞,因为内层通道c和信号通道f都没有数据可读。由于main()可以取得内层通道c,并向其发送数据,使得f1()中的select第一个case分支被选中,该分支会计算发送的整数之前的总和,并将计算结果重新发送给内层通道c,让main()可以取得这个计算结果。

上面的示例中有几个细节需要注意:

  1. 在f1()中必须关闭内层通道c,因为main()中的range迭代一个未关闭的通道会一直阻塞,而且每次调用f1()都会重新创建c通道。
  2. 上面的信号通道其实没有起到任何作用。
  3. f1()中的select必须不能放进for循环。因为f1()将数据发回c之后,如果在for中,发f()所在的goroutine将阻塞在select上,由于c通道还没有关闭,这会导致main goroutine因range迭代操作而阻塞,也就是说所有goroutine都被阻塞了,出现了死锁。

所以,当在select中有发送操作的时候,很可能会出现死锁现象。这时,要么为select加上default,要么为select加上超时时间,要么select不要放在for循环中

Go基础系列:双层channel用法示例的更多相关文章

  1. Go基础系列:nil channel用法示例

    Go channel系列: channel入门 为select设置超时时间 nil channel用法示例 双层channel用法示例 指定goroutine的执行顺序 当未为channel分配内存时 ...

  2. Go基础系列:channel入门

    Go channel系列: channel入门 为select设置超时时间 nil channel用法示例 双层channel用法示例 指定goroutine的执行顺序 channel基础 chann ...

  3. Go基础系列:WaitGroup用法说明

    正常情况下,新激活的goroutine的结束过程是不可控制的,唯一可以保证终止goroutine的行为是main goroutine的终止.也就是说,我们并不知道哪个goroutine什么时候结束. ...

  4. Go基础系列:为select设置超时时间

    Go channel系列: channel入门 为select设置超时时间 nil channel用法示例 双层channel用法示例 指定goroutine的执行顺序 After() 谁也无法保证某 ...

  5. Go基础系列:指定goroutine的执行顺序

    Go channel系列: channel入门 为select设置超时时间 nil channel用法示例 双层channel用法示例 指定goroutine的执行顺序 当关闭一个channel时,会 ...

  6. C#基础系列——多线程的常见用法详解

    前言:前面几节分别介绍了下C#基础技术中的反射.特性.泛型.序列化.扩展方法.Linq to Xml等,这篇跟着来介绍下C#的另一基础技术的使用.最近项目有点紧张,所以准备也不是特别充分.此篇就主要从 ...

  7. C#基础系列——委托实现简单设计模式

    前言:上一篇介绍了下多线程的相关知识:C#基础系列——多线程的常见用法详解,里面就提到了委托变量.这篇简单介绍下委托的使用.当然啦,园子里面很多介绍委托的文章都会说道:委托和事件的概念就像一道坎,过了 ...

  8. C#基础系列——一场风花雪月的邂逅:接口和抽象类

    前言:最近一个认识的朋友准备转行做编程,看他自己边看视频边学习,挺有干劲的.那天他问我接口和抽象类这两个东西,他说,既然它们如此相像, 我用抽象类就能解决的问题,又整个接口出来干嘛,这不是误导初学者吗 ...

  9. c#基础系列(转)

    转:http://www.cnblogs.com/landeanfen/p/4953025.html C#基础系列——一场风花雪月的邂逅:接口和抽象类 前言:最近一个认识的朋友准备转行做编程,看他自己 ...

随机推荐

  1. Verilog有符号数处理

    内容主要摘自以下两个链接:  https://www.cnblogs.com/LJWJL/p/3481995.html  https://www.cnblogs.com/LJWJL/p/3481807 ...

  2. C++ Thrift服务端记录调用者IP和被调接口方法

    Apache开源的Thrift(http://thrift.apache.org)有着广泛的使用,有时候需要知道谁调用了指定的函数,比如在下线一起老的接口之前,需要确保对这些老接口的访问已全部迁移到新 ...

  3. qscoj 喵哈哈村的打印机游戏 区间dp

    点这里去看题 区间dp ,dp[l][r][d]代表从l到r的区间底色为d,具体看代码 第一次见到区间dp...两个小时对着敲了五遍终于自己敲懂了一遍ac #include<bits/stdc+ ...

  4. gc的real时间比user时间长

    https://stackoverflow.com/questions/556405/what-do-real-user-and-sys-mean-in-the-output-of-time1 htt ...

  5. Hive数据仓库之快速入门

    Hive定位:ETL(数据仓库)工具 将数据从来源端经过抽取(extract).转换(transform).加载(load)至目的端的工具,如像:kettle 有关Hive数据导入导出mysql的问题 ...

  6. sql并集union和union all的区别

    union : 对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序; union all:  对两个结果集进行并集操作,包括重复行,不进行排序; intersect : 对两个结果集进行交 ...

  7. 虚拟机安装ssh,关闭防火墙

    输入命令:sudo apt-get install openssh-server        安装ssh 安装完成后,开启服务 sudo /etc/init.d/ssh start 之后使用如下命令 ...

  8. Java学习笔记一:数据类型I

    GitHub代码练习地址:https://github.com/Neo-ML/JavaPractice/blob/master/IntPractice1.java https://github.com ...

  9. 第47节:Java当中的基本类型包装类

    Java当中的基本类型包装类 01 基本数据类型对象的包装类 什么是基本数据类型对象包装类呢?就是把基本数据类型封装成对象,这样就可以提供更多的操作基本数值的功能了. 基本数据类型对象的包装类8个: ...

  10. 多线程 start 和 run 方法到底有什么区别?

    昨天栈长介绍了<Java多线程可以分组,还能这样玩!>线程分组的妙用.今天,栈长会详细介绍 Java 中的多线程 start() 和 run() 两个方法,Java 老司机请跳过,新手或者 ...