dppi5167 2018-01-30 17:52
浏览 29
已采纳

在具有选择大小写和默认值的Goroutines中,一旦通道关闭,默认值就不会执行

I am trying to understand the behaviour of closed channel in a select block with default case, but got confused with this following output. Here am invoking 50 goroutines and closing the finish channel.

func testClosedChannelBehavior() {
    const n = 50
    finish := make(chan bool)
    var done sync.WaitGroup
    for i := 0; i < n; i++ {
        done.Add(1)
        go func(x int) {
            select {
            case <-time.After(1 * time.Hour):
            case <-finish:
                fmt.Printf("received finish %d
", x)
            default:
            fmt.Printf("I didnt wait %d
", x)
            }
            done.Done()
        }(i)
    }
    t0 := time.Now()
    close(finish) 
    fmt.Println("finish closed")
    done.Wait() 
    fmt.Printf("Waited %v for %d goroutines to stop
",     time.Since(t0), n)
}

I expected once any goroutine prints "received finish", default case should not get executed by any other goroutines i.e. "I didnt wait" should not get printed. But the output is not consistent. At times it behaves as expected, but on running multiple times, I could see unexpected output as below: =====output====== I didnt wait 0 received finish 7 finish closed received finish 13 received finish 10 received finish 32 received finish 5 received finish 14 received finish 33 received finish 42 received finish 11 received finish 4 received finish 23 received finish 44 received finish 49 received finish 15 received finish 24 received finish 31 received finish 16 received finish 40 received finish 41 received finish 6 received finish 26 I didnt wait 1 received finish 19 received finish 8 received finish 43 received finish 29 received finish 20 received finish 46 received finish 12 received finish 36 received finish 47 received finish 37 received finish 35 received finish 30 received finish 39 received finish 22 received finish 28 I didnt wait 2 received finish 17 received finish 45 I didnt wait 9 received finish 48 received finish 34 I didnt wait 3 received finish 25 received finish 38 received finish 27 received finish 18 received finish 21 Waited 394.999µs for 50 goroutines to stop

I was going through this link expecting close(finish) would signal others, those still waiting, to behave alike.

  • 写回答

1条回答 默认 最新

  • doufei2194 2018-01-30 18:03
    关注

    Calls to fmt.Printf involve a syscall. Syscalls automatically cause that goroutine to be rescheduled, as it has to wait on the OS to finish that syscall. That means it's very possible for some of those goroutines to run the select statement and select the default case, but not print to console yet.

    Edit: Also, if you're running this on a system with more than one thread, the go runtime by default will run several go routines in parallel (matching the number of OS threads), meaning some of those goroutines could be executing at the same time as the channel close and reach the select statement before the channel close occurs in the main goroutine.

    If you add in a sync channel to ensure that the channel close operation occurs before the select happens in any of the goroutines, it works as expected:

    https://play.golang.org/p/XtUYaihKgRT

    func testClosedChannelBehavior() {
        const n = 50
        finish := make(chan bool)
        proceed := make(chan struct{})
        var done sync.WaitGroup
        for i := 0; i < n; i++ {
            done.Add(1)
            go func(x int) {
                <-proceed
                select {
                case <-time.After(1 * time.Hour):
                case <-finish:
                    fmt.Printf("received finish %d
    ", x)
                default:
                    fmt.Printf("I didnt wait %d
    ", x)
                }
                done.Done()
            }(i)
        }
        t0 := time.Now()
        close(finish)
        fmt.Println("finish closed")
        close(proceed)
        done.Wait()
        fmt.Printf("Waited %v for %d goroutines to stop
    ", time.Since(t0), n)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置