退出在无缓冲通道上等待的多个 go 例程

我试图同时退出多个戈鲁廷。根据 https://www.godesignpatterns.com/2014/04/exiting-multiple-goroutines-simultaneously.html 有一个明确的方法来做到这一点。


我看到的另一种方法是以下


package main


import (

    "fmt"

    "time"

)


func main() {

    var inCh chan int = make(chan int, 100)

    var exit chan bool = make(chan bool)


    for i := 0; i < 20; i++ {

        go func(instance int) {

            fmt.Println("In go routine ", instance)

            for {

                select {

                case <-exit:

                    fmt.Println("Exit received from ", instance)

                    exit <- true

                    return

                case value := <-inCh:

                    fmt.Println("Value=", value)

                }

            }

        }(i)

    }


    time.Sleep(1 * time.Second)


    exit <- true

    <-exit   // Final exit

    fmt.Println("Final exit")

}

但是我很困惑,我真的不明白为什么最后的无缓冲通道被执行为最后一个语句。实际上,我有20个go例程在听出口频道。随机一个人将收到它并将其发送给另一个人。为什么总是在go例程中进行接收,并且只有当所有例程都完成时,才会执行带有注释“//Final Exit”的通道接收?


如果有人能给我一个解释,我将不胜感激。


泛舟湖上清波郎朗
浏览 66回答 3
3回答

MMTTMM

用于取消,如链接文章中所示。close()有问题的代码不能保证工作。下面是它失败的场景:一个戈鲁丁已准备好从 接收。所有其他戈鲁丁人都在其他地方忙碌。exitmain 发送的值由准备好的戈鲁廷接收。该戈鲁廷向 接收的值发送一个值。exitmain()其他戈鲁廷不会退出,因为没有更多的值被发送到 。请参阅此使用时间的游乐场示例。渗漏以诱导问题场景。exit为什么总是在go例程中进行接收,并且只有当所有例程都完成时,才会执行带有注释“//Final Exit”的通道接收?该程序的执行方式就好像通道维护着一个有序的等待戈鲁丁队列,但规范中没有任何内容可以保证该行为。即使通道具有有序队列,如果 goroutine 正在执行某些操作而不是等待从 接收,则程序也可能会遇到上述情况。exit

qq_笑_17

如果您注意到程序的输出In go routine&nbsp; 6In go routine&nbsp; 0In go routine&nbsp; 7..Exit received from&nbsp; 6Exit received from&nbsp; 0Exit received from&nbsp; 7..Final exit它们以相同(或几乎相同)的顺序被调用,这些顺序与它们的启动方式相同。如果您的 Go 例程都不繁忙,则将使用第一个注册的例程。这只是运行时的实现,我不会指望这种行为。您的最终出口是最后一个要收听的通道,因此最后使用它。如果删除时间。循环后睡觉,您的最终出口几乎会立即被调用,并且您的大多数go例程都不会收到退出信号输出与时间输出。睡眠(在跑步之间会非常多)In go routine&nbsp; 0Exit received from&nbsp; 0In go routine&nbsp; 1In go routine&nbsp; 2In go routine&nbsp; 3In go routine&nbsp; 4In go routine&nbsp; 5In go routine&nbsp; 6In go routine&nbsp; 7In go routine&nbsp; 14In go routine&nbsp; 15In go routine&nbsp; 16In go routine&nbsp; 17In go routine&nbsp; 18In go routine&nbsp; 19Final exit

四季花海

请考虑此轻微修改。package mainimport (&nbsp; &nbsp; "fmt")func main() {&nbsp; &nbsp; var exit chan int = make(chan int)&nbsp; &nbsp; &nbsp; &nbsp; var workers = 20&nbsp; &nbsp; for i := 0; i < workers; i++ {&nbsp; &nbsp; &nbsp; &nbsp; go func(instance int) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("In go routine ", instance)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case i := <-exit:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Exit", i, "received from ", instance)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exit <- i-1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }(i)&nbsp; &nbsp; }&nbsp; &nbsp; exit <- workers&nbsp; &nbsp; fmt.Println("Final exit:", <-exit)}在这里,我做了3件事:首先,为了简洁起见,我删除了未使用的频道。其次,我消除了睡眠。第三,我将通道更改为每次通过都会递减的通道。如果我传入工作人员的数量,则除“最终”消息以外的任何值都表示工作人员被丢弃。exitint0下面是一个运行示例:% go run t.goIn go routine&nbsp; 8In go routine&nbsp; 5In go routine&nbsp; 0In go routine&nbsp; 2Exit 20 received from&nbsp; 8Exit 19 received from&nbsp; 5Final exit: 18In go routine&nbsp; 13当呼叫时,直到睡眠结束才会安排。其他哥鲁丁都有这个时间来设置他们的频道阅读器。我只能假设,因为我在任何地方都找不到它,频道读者很可能在大致的时间顺序错误中排队 - 因此,保证读者是最后一个。maintime.Sleepsleepmain如果这是一致的行为,那肯定是不可靠的。请参阅在一个频道上收听多个戈鲁丁,以获取有关此内容的更多想法。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go