[英]exiting multiple go routines waiting on an unbuffered channel
我試圖同時退出多個 Goroutines。 根據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”的通道接收?
如果有人能給我一個解釋,我將不勝感激。
如鏈接文章中所示,使用close()
進行取消。
有問題的代碼不能保證工作。 這是一個失敗的場景:
exit
接收。 所有其他 goroutines 在其他地方忙。exit
發送一個值,該值由main()
接收。 其他 goroutine 不會退出,因為沒有更多的值被發送到exit
。 請參閱這個使用 time.Seep 來引發問題場景的游樂場示例。
為什么go例程中的接收總是在發生,只有當所有例程都完成時,才會執行注釋為“// Final Exit”的通道接收?
該程序的執行就像通道維護一個有序的等待 goroutines 隊列一樣,但規范中沒有任何內容可以保證該行為。 即使通道有一個有序隊列,如果 goroutine 正在做一些事情而不是等待從exit
接收,程序也會遇到上面的場景。
如果你注意到你程序的 output
In go routine 6
In go routine 0
In go routine 7
.
.
Exit received from 6
Exit received from 0
Exit received from 7
.
.
Final exit
他們以與他們開始時相同(或幾乎相同)的順序被調用。 如果您的 Go 例程都不忙,將使用第一個注冊的例程。 這只是運行時的一個實現,我不會指望這種行為。
您的最終退出是要收聽的最后一個頻道,因此最后使用。
如果你刪除 time.Sleep 在你的循環之后你的最終退出將幾乎立即被調用並且你的大部分 go 例程將不會收到退出信號
Output 沒有時間。睡眠(將在運行之間)
In go routine 0
Exit received from 0
In go routine 1
In go routine 2
In go routine 3
In go routine 4
In go routine 5
In go routine 6
In go routine 7
In go routine 14
In go routine 15
In go routine 16
In go routine 17
In go routine 18
In go routine 19
Final exit
考慮這個輕微的修改。
package main
import (
"fmt"
)
func main() {
var exit chan int = make(chan int)
var workers = 20
for i := 0; i < workers; i++ {
go func(instance int) {
fmt.Println("In go routine ", instance)
for {
select {
case i := <-exit:
fmt.Println("Exit", i, "received from ", instance)
exit <- i-1
return
}
}
}(i)
}
exit <- workers
fmt.Println("Final exit:", <-exit)
}
在這里,我做了三件事:首先,為簡潔起見,我刪除了未使用的頻道。 其次,我刪除了睡眠。 第三,我將exit
通道更改為每次通過都會遞減的int
通道。 如果我傳遞工人的數量,“最終”消息中除0
以外的任何值都表示工人被丟棄。
這是一個示例運行:
% go run t.go
In go routine 8
In go routine 5
In go routine 0
In go routine 2
Exit 20 received from 8
Exit 19 received from 5
Final exit: 18
In go routine 13
當main
調用time.Sleep
時,直到睡眠結束才會安排它。 其他 goroutines 都有這個時間來設置他們的頻道閱讀器。 我只能假設,因為我在任何地方都找不到它,通道讀者可能會大致按時間順序排隊 - 因此, sleep
保證main
的讀者是最后一個。
如果這是一貫的行為,那肯定是不可靠的。
請參閱多個 goroutines listening on one channel了解更多關於此的想法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.