douqian8238 2014-10-01 06:49
浏览 73
已采纳

理解代码-并发模式:菊花链

I was studying Go concurrency pattern.

One pattern I am not sure is: Daisy Chain https://talks.golang.org/2012/concurrency.slide#39

It's very hard for me to understand the control flow of the code.

Can someone explain to me ?

package main

import (
    "fmt"
)

func f(left, right chan int) {
    left <- 1 + <-right
}

func main() {
    const n = 10000

    leftmost := make(chan int)
    right := leftmost               //point B: what does these do ?
    left := leftmost

    for i := 0; i < n; i++ {
        right = make(chan int)
        go f(left, right)
        left = right                //point A
    }
    go func(c chan int) { c <- 1 }(right)  
    fmt.Println(<-leftmost)
}

Conclusion:

  1. the flow of channel going from right to left. It is good practice to write func f(left chan<- int, right <-chan int) rather than original function signature as above.

  2. 'chain reaction' does not start until c <- 1, when signal 1 is sent to right most channel, reaction goes all the way to left most end. Print out 10001.

The reason is go channel block 'read' until received channel receive signal.

  1. @Rick-777 shows how to use array like structure for easy understanding. Since each go coroutine is just around 6k big. It's not a bad idea to make 10k channel.

  2. I clean up some code around Point B, for channel initialization. Here is the source code: http://play.golang.org/p/1kFYPypr0l

  • 写回答

2条回答 默认 最新

  • dongsuikai8286 2014-10-02 11:28
    关注

    VonC has already given a direct answer. Here are some further remarks.

    A slightly tidied-up version is in the playground, the difference being that the channels passed as parameters have their direction specified explicitly, ie. <-chan and chan<-. It's good practice to do this because the compiler can catch more mistakes for you.

    An alternative and equivalent program that has a daisy-chain of n goroutines can be written using an array of channels instead. This allocates the same total number of channels using fewer lines of code. See playground:

    package main
    
    import (
        "fmt"
    )
    
    func f(left chan<- int, right <-chan int) {
        left <- 1 + <-right
    }
    
    func main() {
        const n = 10000
    
        // first we construct an array of n+1 channels each being a 'chan int'
        var channels [n+1]chan int
        for i := range channels {
            channels[i] = make(chan int)
        }
    
        // now we wire n goroutines in a chain
        for i := 0; i < n; i++ {
            go f(channels[i], channels[i+1])
        }
    
        // insert a value into the right-hand end
        go func(c chan<- int) { c <- 1 }(channels[n])
    
        // pick up the value emerging from the left-hand end
        fmt.Println(<-channels[0])
    }
    

    I hope you can see now how the original program is equivalent to this program. There is one minor difference: the original program does not create any channel array, so uses just a little less memory.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler