Bei der gleichzeitigen Programmierung stoßen wir oft auf Situationen, in denen wir warten müssen, bis alle Goroutinen abgeschlossen sind, bevor wir mit der Ausführung fortfahren. In der Go-Sprache können wir dieses Ziel erreichen, indem wir WaitGroup verwenden. WaitGroup ist ein Zählsemaphor, mit dem auf den Abschluss einer Gruppe von Goroutinen gewartet werden kann. Bevor wir fortfahren, müssen wir die Wait-Methode von WaitGroup aufrufen, um sicherzustellen, dass alle Goroutinen ihre Aufgaben abgeschlossen haben. In diesem Artikel stellen wir vor, wie WaitGroup korrekt zum Verwalten der Ausführungsreihenfolge von Goroutinen verwendet wird.
Ich benötige den Golang-Scheduler, um alle Goroutinen auszuführen, bevor ich fortfahre. runtime.gosched() kann das Problem nicht lösen.
Das Problem ist, dass die Go-Routine so schnell läuft, dass das „select“ in start() nach dem „select“ in stopstream() ausgeführt wird und dann „case <-chanstopstream:“ der Empfänger nicht für den Sender „case“ bereit ist retchan <-true:". Es stellt sich heraus, dass in diesem Fall das gleiche Verhalten auftritt wie wenn stopstream() hängt
Führen Sie diesen Code aus https://go.dev/play/p/dq85xqju2q_z Oft werden Sie diese beiden Antworten sehen Erwartete Antwort, wenn nicht suspendiert:
2009/11/10 23:00:00 start 2009/11/10 23:00:00 receive chan 2009/11/10 23:00:03 end
Erwartete Reaktion bei Suspendierung, aber nicht so schnell bei Suspendierung:
2009/11/10 23:00:00 start 2009/11/10 23:00:00 default 2009/11/10 23:00:01 timer 2009/11/10 23:00:04 end
Code
package main import ( "log" "runtime" "sync" "time" ) var wg sync.WaitGroup func main() { wg.Add(1) //run multiples routines on a huge system go start() wg.Wait() } func start() { log.Println("Start") chanStopStream := make(chan bool) go stopStream(chanStopStream) select { case <-chanStopStream: log.Println("receive chan") case <-time.After(time.Second): //if stopStream hangs do not wait more than 1 second log.Println("TIMER") //call some crash alert } time.Sleep(3 * time.Second) log.Println("end") wg.Done() } func stopStream(retChan chan bool) { //do some work that can be faster then caller or not runtime.Gosched() //time.Sleep(time.Microsecond) //better solution then runtime.Gosched() //time.Sleep(2 * time.Second) //simulate when this routine hangs more than 1 second select { case retChan <- true: default: //select/default is used because if the caller times out this routine will hangs forever log.Println("default") } }
Es gibt keine Möglichkeit, alle anderen Goroutinen auszuführen, bevor die Ausführung der aktuellen Goroutine fortgesetzt wird.
Das Problem wurde behoben, indem sichergestellt wurde, dass die Goroutine nicht blockiert stopstream
:
Option 1: Ändern Sie chanstopstream
in gepufferter Kanal chanstopstream
更改为缓冲通道。这确保了 stopstream
. Dadurch wird sichergestellt, dass
func start() { log.println("start") chanstopstream := make(chan bool, 1) // <--- buffered channel go stopstream(chanstopstream) ... } func stopstream(retchan chan bool) { ... // always send. no select/default needed. retchan <- true }
Option 2
: Schließen Sie den Kanal, anstatt den Wert zu senden. Kanäle können jederzeit vom Absender geschlossen werden. Empfängt einen Nullwert auf einem geschlossenen Kanal, der den Kanalwerttyp zurückgibt.
func start() { log.Println("Start") chanStopStream := make(chan bool) // buffered channel not required go stopStream(chanStopStream) ... func stopStream(retChan chan bool) { ... close(retChan) }
Das obige ist der detaillierte Inhalt vonBitten Sie Go, alle Goroutinen auszuführen, bevor Sie fortfahren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!