Heim  >  Artikel  >  Backend-Entwicklung  >  Sicherer Weg, Endlosschleifen-Goroutine zu beenden?

Sicherer Weg, Endlosschleifen-Goroutine zu beenden?

WBOY
WBOYnach vorne
2024-02-06 09:09:04967Durchsuche

终止无限循环 goroutine 的安全方法?

Frageninhalt

Ich habe eine Goroutine, die als Zuhörer fungiert. Der Eingabestream kommt in eine Art gepuffertes channel,我希望我的 goroutine 处理传入该通道的数据。然而,有时 channel 可能会暂时没有数据输入。如果 channel, das für eine Sekunde nichts zu bieten hat und ich möchte, dass meine Goroutine etwas anderes macht. Die Funktion sieht so aus:

func main () {
    var wg sync.WaitGroup
    arr := make([]*myObject, 0)
    wg.Add(1)
    go listener(c, arr, &wg)
    for {
        // sending stuff to c
    }
}

func listener(c chan *myObject, arr []*myObject, wg *sync.WaitGroup) {
    for {
        select {
        case value := <- c:
            arr = append(arr, value)
        case <- time.After(1 * time.Second):
            fmt.Println(arr)
        }
}

Das Problem ist, dass ich alles gedruckt sehen möchte, was über diesen Kanal geht. Wenn die Position von main 突然结束,可能 arr 中还剩下一些东西还没有打印出来,我就看不到了。所以我需要确保这个goroutine在程序结束之前处理完通道中的所有数据。我认为,这意味着我需要使用 WaitGroup 并使用 Wait() 来确保程序在我的 goroutine 完成需要执行的操作之前不会关闭。 但我不知道在我的 WaitGroup 上调用 Done().

Grundsätzlich brauche ich eine sichere Möglichkeit, die Goroutine vor Programmende „anzuhalten“ und den Rest auszudrucken. Wie kann ich das machen?

Erschwerend kommt hinzu, dass ich für Dinge wie Unit-Tests selbst Daten an den Kanal sende und nach dem Senden einer bestimmten Menge das Array anzeigen möchte. Wenn ich jedoch nur das Array direkt nach dem Code überprüfe, der die Daten an den Kanal sendet, hatte die Goroutine möglicherweise noch keine Chance, alle Daten zu verarbeiten. In diesem Fall möchte ich warten, bis die Goroutine alle von mir gesendeten Daten verarbeitet hat, und sie dann anhalten und bitten, mir das Array anzuzeigen. Aber woher weiß ich, wann die Goroutine mit der Verarbeitung fertig ist? Ich könnte sleep eine Weile warten, ihm eine Chance geben, fertig zu werden, und dann innehalten und es mir ansehen, aber das fühlt sich ziemlich kitschig an. Ich denke, es gibt eine Best-Practice-Methode, um dieses Problem zu lösen, aber ich habe es noch nicht herausgefunden.

Hier sind einige Ideen, die ich hatte, keine davon hat funktioniert.

  1. in der Unendlichkeit for 循环之外调用 Done(). Das funktioniert nicht, da der Code meines Wissens nicht zugänglich ist.

  2. Im Timeoutcase中调用Done(). Dies funktioniert nicht, da nach dem Timeout möglicherweise weitere Daten unterwegs sind und ich möchte, dass meine Goroutine weiter zuhört.


Richtige Antwort


Ändern Sie den Hörer so, dass er zurückkehrt, wenn der Kanal geschlossen wird. Rufen Sie wg.Done() bei der Rückkehr auf:

func listener(c chan *myObject, arr []*myObject, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        select {
        case value, ok := <- c:
            if !ok { return }
            arr = append(arr, value)
        case <- time.After(1 * time.Second):
            fmt.Println(arr)
        }
}

Ändern Sie main, um den Kanal zu schließen, nachdem der Versand abgeschlossen ist. Warten Sie, bis die Goroutine abgeschlossen ist, bevor Sie von der Hauptroutine zurückkehren.

var wg sync.WaitGroup
arr := make([]*myObject, 0)
wg.Add(1)
go listener(c, arr, &wg)
for {
    // sending stuff to c
}
close(c)
wg.Wait()

Das obige ist der detaillierte Inhalt vonSicherer Weg, Endlosschleifen-Goroutine zu beenden?. 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