ホームページ >バックエンド開発 >Golang >Go で長時間実行されるコマンドから部分的な出力をストリーミングする方法は?

Go で長時間実行されるコマンドから部分的な出力をストリーミングする方法は?

Mary-Kate Olsen
Mary-Kate Olsenオリジナル
2024-12-24 00:18:15845ブラウズ

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

コマンド出力の進行状況のストリーミング

長時間実行されるコマンドが実行され、その出力を親プロセスとログ ファイルの両方に継続的にストリーミングする必要があるシナリオ、 cmd.StdoutPipe() メソッドを利用して出力をキャプチャできます。

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()

ただし、このアプローチでは、部分的な結果をストリーミングするのではなく、単一の文字列として最終出力します。

出力が制限される理由

bufio.NewScanner() 関数は行に対して動作し、改行文字が出現すると完全な行を返します。実行中のコマンドで改行文字が生成されない場合、出力はすぐにはストリーミングされません。

考えられる回避策

この制限に対処するには、考慮すべきアプローチがいくつかあります。

  1. 単語または文字で読む:
    分割を設定するScanner.Split() を使用する関数を使用すると、単語または文字で入力をスキャンし、生成された出力をキャプチャできます。

    scanner := bufio.NewScanner(stdout)
    scanner.Split(bufio.ScanRunes)
  2. マニュアル読み取り:
    バイトごとまたはルーンごとに読み取ることで、改行に依存せずに生成された出力をキャプチャできます

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

考慮事項

子プロセスの標準出力およびエラー ストリームのバッファ サイズを管理することが重要です。デフォルトでは、これらのバッファーが読み取られない場合、子プロセスがハングする可能性があります。したがって、常に stdout ストリームと stderr ストリームの両方を読み取ることをお勧めします。

以上がGo で長時間実行されるコマンドから部分的な出力をストリーミングする方法は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。