dongshan2680 2018-07-04 07:20
浏览 8

在单个“选择”情况下的链接通道操作

I try to multiplex 2 channels, A and B. A is sending with 10 milliseconds delay and B is 1 second. I use select to wait for A and B, and send the result to a fan-in channel, and then receive value in main.

package main

import  (
"fmt"
"time"
)

func talk(msg string, wait_time int) <-chan string {
    ch := make(chan string)
    go func () {
        for i:=0;i<5;i++ {
            ch <- fmt.Sprintf("%s %d", msg, i)
            time.Sleep(time.Duration(wait_time)*time.Millisecond)
        }
    }()

    return ch
}

func fanIn(input1, input2 <-chan string) <-chan string {
    ch := make(chan string)
    go func () {
        for {
            select {
                case t :=<-input1:
                    ch <- t
                case t := <-input2:
                    ch <- t
            }
        }
    }()

    return ch
}
func main() {
    ch := fanIn(talk("A", 10), talk("B", 1000))

    for i:=0; i<10; i++ {
        fmt.Printf("%q
", <-ch)
    }
    fmt.Printf("Done
")

}

This will get the correct result as shown below

"A 0"
"B 0"
"A 1"
"A 2"
"A 3"
"A 4"
"B 1"
"B 2"
"B 3"
"B 4"
Done

My question is, when I change the case statement, I got weird output. it seems some value were dropped, and of course no more value is received in fan-in channel and deadlock happened.

select {
                case ch<- <-input1:
                case ch<- <-input2:
            }

Result is like this:

"B 0"
"A 1"
"B 2"
"A 3"
"A 4"
fatal error: all goroutines are asleep - deadlock!

Anyone has any idea of this situation?

  • 写回答

3条回答 默认 最新

  • dongtan9253 2018-07-04 07:35
    关注

    That happens because in select only one channel read or write is non blocking.

    All other operations behave normally.

    So in this piece of code

    select {
                    case ch<- <-input1:
                    case ch<- <-input2:
                }
    

    it receives a value from input1 (blocking). It waits for a delay and receives A 0.

    It tries to write it to ch, non blocking.

    If the code in main was fast enough to reach

     fmt.Printf("%q
    ", <-ch)
    

    line then write to a channel succeeds.

    Then fanIn for loop starts second iteration: it picks the second case this time (it's not deterministic). At this point it's likely that the second goroutine has written the B 0 value.

    But there is a chance that the main function loop has not consumed the value from the combined channel.

    So the value is dropped.

    This repeats multiple times, you lose few values and end up having no writers and a reader waiting for the remaining values forever.

    This slightly modified copy of code demonstrates it: https://play.golang.org/p/lcM5OKx09Dj

    评论

报告相同问题?

悬赏问题

  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?