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. c语言小程序以及java生成注释文档方法

    c语言小程序:sizeof和strlen() sizeof运算符以字节为单位给出数据的大小,strlen()函数以字符为单位给出字符串的长度,字符和字节不是一回事. char类型用于存储字母和标点符号 ...

  2. 6-使用requests库封装类处理get/post请求

    1.request安装 1)pip安装,直接pip install requests 2)下载离线包安装,加压后,命令行进入路径,执行python setup.py install 2.创建工程 注意 ...

  3. XML学习总结一

    1.声明 <?xml version="1.0"  encoding="gb2312"?> version属性指定该文档遵守的版本号,通常为1.0X ...

  4. Calendar and GregorianCalendar

    1.GregorianCalendar是Calendar的一个具体子类,提供了世界上大多数国家/地区使用的标准日历系统 2.注意 (1)月份:1月到12月[0-11] (2)星期:周日到周六[1-7] ...

  5. Codeforces Round #425 (Div. 2)

    A 题意:给你n根棍子,两个人每次拿m根你,你先拿,如果该谁拿的时候棍子数<m,这人就输,对手就赢,问你第一个拿的人能赢吗 代码: #include<stdio.h>#define ...

  6. 【备忘】ASP.NET MVC 5 升级到 ASP.NET Core MVC 的部分变化

    正在将一个 .net 4.5 的项目(MVC 5)升级到 .net core 2.1,中间遇到了许多的修改,记在下面,帮大家少走弯路. System.Drawing 下面很多类已经不存在(如Bitma ...

  7. Javascript高级编程学习笔记(35)—— DOM(1)节点

    DOM JS由三部分组成 1.BOM 2.DOM 3.ECMAScript ES和BOM在前面的文章已经介绍过了 今天开始JS组成的最后一部分DOM(文档对象模型) 我们知道,JS中的这三个部分实际上 ...

  8. Javascript高级编程学习笔记(24)—— 函数表达式(2)闭包

    昨天的文章中主要记录了,函数表达式与函数声明的区别 以及在JS中如何安全地使用递归 那么既然要深入地理解JS中的函数,闭包就是一个绕不开的概念 闭包 JS高编一书中对闭包的概念定义如下: 闭包是指有权 ...

  9. Javascript高级编程学习笔记(22)—— 对象继承

    继承是所有面向对象的语言最让人津津乐道的概念 许多面向对象的语言都支持两种实现继承的方式: 1.接口继承 2.实现继承 由于ECMAScript中没有函数签名,所以自然也是不支持接口继承 所以JS中能 ...

  10. 2.抽取代码(BaseActivity)

    知识点 俩种退出程序的方法 复制集合 同步的用法 字符数组 工厂模式,生产fatgment,解决了碎片重复创建的问题 全局上下文 actionbar用法 fargmentadapter,当viewpa ...