Rob Pike 在 Google I/O 2012 - Go Concurrency Patterns 里演示了一个例子(daisy chain)。 视频地址:https://www.youtube.com/watch?v=f6kdp27TYZs

这个例子抽象于“传话游戏”,几个人站成一队,第一个人跟第二个人悄悄说一句话,依次传到最后一个人,看看最后一个人听到的和第一个人说的差别有多大。

代码如下:

package main

import "fmt"

func pass(left, right chan int){
left <- 1 + <- right
} func main(){
const n = 50
leftmost := make(chan int)
right := leftmost
left := leftmost for i := 0; i< n; i++ {
right = make(chan int)
// the chain is constructed from the end
go pass(left, right) // the first goroutine holds (leftmost, new chan)
left = right // the second and following goroutines hold (last right chan, new chan)
}
go func(c chan int){ c <- 1}(right)
fmt.Println("sum:", <- leftmost)
}

这段代码产生了一个单向的管道环,每个节点对输入的值加了1,然后输出给下一个节点,最后到终点 leftmost。重点我认为有以下几个:

1,循环中的 goroutine ;

2,unbuffered channel 的连接和阻塞;

3,goroutine 对 channel 的竞争;

第一点:循环中的 goroutine 其实很像 js 中的循环中的异步请求,或者更直观的,像是循环中的 setTimeout()。对于 main 来说,goroutine 是异步的,是对线程的细粒度抽象,把它当做一个异步任务就可以了。但是包含了 channel 的 goroutine 就有了阻塞的成分。channel 也体现了 Golang 的设计理念之一:Do not communicate by sharing memory; instead, share memory by communicating 。

第二点:unbuffered channel (make(chan int)) 可以看做是非常短的管子,里面连一个字节都不能存储,必须先找到两端的输入和输出,不然就会出问题(阻塞)。比如下面代码:

func main(){
c := make(chan int)
c <- 1
fmt.Println( <- c)
} // fatal error: all goroutines are asleep - deadlock!

上面的代码中, c <- 1 这一行给 channel 输入了数据,但是此时还没有接收者(代码是同步执行的),因此卡死在这儿了。

那如果先给 channel 指定了输出,然后再输入数据呢? 结果是一样的,只有接收者没有输入者,一样卡死。

改成这样就可以了:

func main(){
c := make(chan int)
go func(){fmt.Println(<- c)}()
c <- 1
}

这里先在 goroutine 里指定了 Println 作为接收者,然后给了输入。

可以理解为:channel 不能同时输入和输出, <- c <- 1  会报错(可能 Golang 觉得这样是没有意义的);指定输入和输出必须写在两行,而代码的同步执行决定了不能同时指定输入和输出,因此只能用 goroutine 。实际上 channel 本身也是为了 goroutine 间的通讯。

buffered channel 就比较好理解,是带有容器的管道,可以存储一定数量的数据。但是当容器满的时候,表现就和 unbuffered channel 一样,会阻塞。

第三点:第一块代码里产生的管道环是从终点开始连接起的,最后一根管道实际上是数据流的第一节管道。在这个环刚完成的时候,所有管道都是空的,没有输入。这时所有的 goroutine 都被阻塞了,倒数第三行的 go 给了第一个管道一个输入,于是这点数据就流到了最后。

一个Golang例子:for + goroutine + channel的更多相关文章

  1. golang并发编程goroutine+channel(一)

    go语言的设计初衷除了在不影响程序性能的情况下减少复杂度,另一个目的是在当今互联网大量运算下,如何让程序的并发性能和代码可读性达到极致.go语言的并发关键词 "go" go dos ...

  2. Golang之chan/goroutine(转)

    原文地址:http://tchen.me/posts/2014-01-27-golang-chatroom.html?utm_source=tuicool&utm_medium=referra ...

  3. Go语言学习笔记(七)杀手锏 Goroutine + Channel

    加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 Goroutine Go语言的主要的功能在于令人简易使用的并行设计,这个方法叫做Goroutine,通过Gorou ...

  4. Golang学习笔记:channel

    channel channel是goroutine之间的通信机制,它可以让一个goroutine通过它给另一个goroutine发送数据,每个channel在创建的时候必须指定一个类型,指定的类型是任 ...

  5. golang学习笔记 --- goroutine

    package main import ( "fmt" "io" "io/ioutil" "net/http" &quo ...

  6. 使用goroutine+channel和java多线程+queue队列的方式开发各有什么优缺点?

    我感觉很多项目使用java或者c的多线程库+线程安全的queue数据结构基本上可以实现goroutine+channel开发能达到的需求,所以请问一下为什么说golang更适合并发服务端的开发呢?使用 ...

  7. 开源一个golang小程序商城后台系统(moshopserver)

    开源一个golang小程序商城后台(moshopserver) golang和c/c++比起来是一门新的语言,一直想学,网上搜集了一些资料,有些人说很容易上手,确实是这样,和C/C++比起来,少了很多 ...

  8. 【转】关于 Goroutine Channel Select 的用法和理解

    原文:https://blog.csdn.net/jfkidear/article/details/88661693 ----------------------------------------- ...

  9. 从0写一个Golang日志处理包

    WHY 日志概述 日志几乎是每个实际的软件项目从开发到最后实际运行过程中都必不可少的东西.它对于查看代码运行流程,记录发生的事情等方面都是很重要的. 一个好的日志系统应当能准确地记录需要记录的信息,同 ...

随机推荐

  1. codeblocks中cocos2dx项目添加新的.cpp和.h文件后编译运行的方法

    新建了cocos2dx项目后(比如我这里建立的项目名为Test01),项目目录下有如下目录和文件: bin CMakeLists.txt MyGame.layout proj.win10 Classe ...

  2. Oracle类型number与PG类型numeric对比和转换策略

    Oracle 11g number 任意精度数字类型 http://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT3 ...

  3. 腾讯正式开源高性能超轻量级 PHP 框架 Biny

    概况 Biny是一款高性能的超轻量级PHP框架 遵循 MVC 模式,用于快速开发现代 Web 应用程序 Biny代码简洁优雅,对应用层,数据层,模板渲染层的封装简单易懂,能够快速上手使用 高性能,框架 ...

  4. Excel 2010 Alt+; (分号) --- “只选定当前选定区域中的可视单元格”

    excel怎样把筛选出来的加上颜色? 1.选中筛选结果数据区域: 2.同时按下Alt+; (分号)键,选中筛选出的数据: 3.鼠标右键,设置单元格格式: 4.在弹出的对话框中,设置字体.背景颜色,即可 ...

  5. linux如何设置用户权限

    linux与用户权限设置: 1.添加用户 首先用adduser命令添加一个普通用户,命令如下: #adduser tommy //添加一个名为tommy的用户 #passwd tommy //修改密码 ...

  6. js+jquery

    改变元素的不透明度 <!DOCTYPE html> <html> <head> <script> function ChangeOpacity(x) { ...

  7. MACOS配置VIM成简单IDE傻瓜式操作

    零.参考文献: https://www.jianshu.com/p/f0513d18742a 一.安照我的配置:保存文件 " Configuration file for vim " ...

  8. Mysql和sqlite数据库操作心得

    经过最近一段时间的实际工作发现,原来只是认为Mysql和sqlite是分别独立的,数据传输和共享或有障碍,其实这是一个误区.当我们想要将sqlite中的数据存放到mysql中,最好的方法就是利用中间文 ...

  9. ORA-39006、ORA-39065、ORA-01403、ORA-39097错误解决办法

    今天有同事找说是expdp到出数据时报错: 处理方法:sys用户下执行如下语句重新生成DATAPUMP API用到的视图问题就解决了. SQL> @?/rdbms/admin/catmeta.s ...

  10. 需求:过滤下面这个网页里共723行 校对中里 行数为两位数的 行 并设置sz和rz在Windows和Linux之间发送和接收文件不用搭FTP

    需求:过滤下面这个网页里共723行 校对中里 行数为两位数的 行 并设置sz和rz在Windows和Linux之间发送和接收文件不用搭FTP 需求:过滤下面这个网页里共723行 校对中里 行数为两位数 ...