zoukankan      html  css  js  c++  java
  • 一个Golang例子:for + goroutine + channel

    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 给了第一个管道一个输入,于是这点数据就流到了最后。

  • 相关阅读:
    .net framework 3.5 dotNetFx35setup 能不需要网络支持吗? 
    Android API Differences Report
    Android用户版本分布更新 2.1版领先
    Adobe升级Flash回击批评:流畅播放手机视频
    iPhone OS4.0,Android 2.1和WP7对比分析
    Android 2.2数据共享功能开启与否将由运营商自主决定
    谷歌 Android 3.0计划四季度推出:代号姜饼
    谷歌称Android设备日激活量已达10万台
    iPod Touch也将支持运行Android系统
    Android2.2 SDK正式提供下载
  • 原文地址:https://www.cnblogs.com/jasonxuli/p/6861791.html
Copyright © 2011-2022 走看看