Go os.Exec 输出缓冲区 [重复]

问题描述 投票:0回答:1

我正在尝试从 Go 程序中运行外部进程。我想捕获标准输出流并通过我定制的 Go 记录器将每个输出写入我的 Go 程序的输出。

这就是我目前正在使用的

测试.py:

import time

i = 0
while True:
    print("Python line with lots of content to fill up the buffer more quickly {}".format(i))
    i += 1
    time.sleep(1)

test.go

package main

import (
    "fmt"
    "os/exec"
    "time"
)

type logWriter struct{}

func (lw *logWriter) Write(data []byte) (int, error) {
    fmt.Printf(string(data))
    return len(data), nil
}

func main() {
    execCmd := exec.Command("python3", "./test.py")
    execCmd.Stdout = &logWriter{}
    execCmd.Stderr = &logWriter{}
    if err := execCmd.Start(); err != nil {
        panic(err)
    }

    go func() {
        if err := execCmd.Wait(); err != nil {
            panic(err)
        }
    }()

    j := 0
    for {
        fmt.Printf("Go line %d\n", j)
        j++
        time.Sleep(1 * time.Second)
    }
}

由此,我希望看到 Go 程序输出一行(每 1 秒一次),然后是 Python 程序输出 10 行(每 0.1 秒一次),并且这种模式会重复。

相反,我得到以下输出:

Go line 0
Go line 1
Go line 2
Go line 3
Go line 4
Go line 5
Go line 6
Go line 7
Go line 8
Go line 9
Go line 10
Go line 11
Python line with lots of content to fill up the buffer more quickly 0
Python line with lots of content to fill up the buffer more quickly 1
Python line with lots of content to fill up the buffer more quickly 2
...
Python line with lots of content to fill up the buffer more quickly 114
Go line 12
Go line 13
Go line 14

而且这种模式一直在重复,所以它与启动 Python 程序的延迟无关。

我猜这是

os.Exec
标准输出缓冲的问题。但是,我似乎找不到任何允许减少或删除此输出缓冲区的参数。

理想情况下,我会让 Python 程序中的每个单独的输出语句(例如

print()
)对应于 Go 中的一个
fmt.Printf
语句。有没有办法做到这一点?

go exec output-buffering
1个回答
-3
投票

编辑:对于那些投反对票的人,我发布了一个未经测试的功能来解决问题,在这里我正在编辑适应这个问题的相同功能,我不知道为什么程序员太毒了,而不是投否定票,测试和根据你的家庭作业和你可以问的任何问题调整解决方案,如果你不同意,请发表评论,为什么孩子。

这段代码会帮助你。

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    execute([]string{"-u", "test.py"})
}

// execute ...
func execute(arguments []string) {
    cmd := exec.Command("python3", arguments...)
    cmdPipeOut(cmd)
}

// get the output from command
func cmdPipeOut(cmd *exec.Cmd) {
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }
    cmd.Stderr = cmd.Stdout

    err = cmd.Start()
    if err != nil {
        log.Fatal(err)
    }

    defer cmd.Wait()
    out := make([]byte, 0)
    var lines uint
    var i uint

    for {
        tmp := make([]byte, 1)
        n, err := stdout.Read(tmp)
        if n > 0 {
            if lines == 10 {
                printGoLineWith10PythonLines(i, out)
                out = make([]byte, 0)
                lines = 0
                i++
            }
            
            if tmp[0] != 10 {
                out = append(out, tmp[0])
            } else {
                out = append(out, 10)
                lines++
            }
        }
        if err != nil {
            break
        }
    }
}

func printGoLineWith10PythonLines(i uint, pythonLines []byte) {
    fmt.Printf("GoLine %d\nPythonLines:\n%s\n", i, pythonLines)
}
© www.soinside.com 2019 - 2024. All rights reserved.