Heim  >  Artikel  >  Backend-Entwicklung  >  Bitten Sie Go, alle Goroutinen auszuführen, bevor Sie fortfahren

Bitten Sie Go, alle Goroutinen auszuführen, bevor Sie fortfahren

PHPz
PHPznach vorne
2024-02-11 17:20:17920Durchsuche

在继续之前要求 Go 运行所有 goroutine

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.

Frageninhalt

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")
    }
}

Workaround

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

Werte ohne Blockierung senden kann.

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
}
https://www.php.cn/link/56e48d306028f2a6c2ebf677f7e8f800

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)
}
https://www.php.cn/link/a1aa0c486fb1a7ddd47003884e1fc67f

🎜

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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen