Heim >Backend-Entwicklung >Golang >Wie streame ich die Teilausgabe eines Befehls mit langer Laufzeit in Go?

Wie streame ich die Teilausgabe eines Befehls mit langer Laufzeit in Go?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-12-24 00:18:15811Durchsuche

How to Stream Partial Output from a Long-Running Command in Go?

Streaming des Befehlsausgabefortschritts

In Szenarien, in denen ein lang andauernder Befehl ausgeführt wird und seine Ausgabe kontinuierlich sowohl an den übergeordneten Prozess als auch an eine Protokolldatei gestreamt werden muss , kann die cmd.StdoutPipe()-Methode verwendet werden, um die Ausgabe zu erfassen.

cmd := exec.Command("sh", "-c", "some long runnig task")

stdout, _ := cmd.StdoutPipe()
cmd.Start()

scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
    m := scanner.Text()
    fmt.Println(m)
    log.Printf(m)
}

cmd.Wait()

Dieser Ansatz liefert jedoch nur die endgültige Ausgabe als einzelne Ausgabe Zeichenfolge, kein Streaming von Teilergebnissen.

Gründe für begrenzte Ausgabe

Die Funktion bufio.NewScanner() arbeitet mit Zeilen und gibt eine vollständige Zeile zurück, wenn ein Zeilenumbruchzeichen angetroffen wird. Wenn der ausgeführte Befehl keine Zeilenumbrüche erzeugt, wird die Ausgabe nicht sofort gestreamt.

Mögliche Problemumgehungen

Um diese Einschränkung zu beheben, sind mehrere Ansätze zu berücksichtigen:

  1. Lesen nach Wörtern oder Zeichen:
    Durch Festlegen einer Teilungsfunktion mit Mit Scanner.Split() können Sie die Eingabe nach Wörtern oder Zeichen scannen und die Ausgabe erfassen, während sie erzeugt wird.

    scanner := bufio.NewScanner(stdout)
    scanner.Split(bufio.ScanRunes)
  2. Manuelles Lesen:
    Durch das Byte-für-Byte- oder Rune-für-Rune-Lesen können Sie die Ausgabe erfassen, während sie generiert wird, ohne auf Zeilenumbrüche angewiesen zu sein Zeichen.

    oneByte := make([]byte, 1)
    for {
        _, err := stdout.Read(oneByte)
        if err != nil {
            break
        }
        fmt.Printf("%c", oneByte[0])
    }
    
    oneRune := make([]byte, utf8.UTFMax)
    for {
        count, err := stdout.Read(oneRune)
        if err != nil {
            break
        }
        fmt.Printf("%s", oneRune[:count])
    }

Überlegungen

Es ist wichtig, Puffergrößen für Standardausgaben und Fehlerströme in untergeordneten Prozessen zu verwalten. Wenn diese Puffer nicht gelesen werden, kann dies standardmäßig dazu führen, dass der untergeordnete Prozess hängen bleibt. Daher wird empfohlen, immer sowohl den stdout- als auch den stderr-Stream zu lesen.

Das obige ist der detaillierte Inhalt vonWie streame ich die Teilausgabe eines Befehls mit langer Laufzeit in Go?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn