go - 从 `exec.Cmd` 中获取 "real-time"的输出

标签 go exec stdout buffering

这个问题类似于Golang - Copy Exec output to Log除了它与 exec 命令输出的缓冲有关。

我有以下测试程序:

package main

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

func main() {
    cmd := exec.Command("python", "inf_loop.py")
    var out outstream
    cmd.Stdout = out
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }
    fmt.Println(cmd.Wait())
}

type outstream struct{}

func (out outstream) Write(p []byte) (int, error) {
    fmt.Println(string(p))
    return len(p), nil
}
上面提到的

inf_loop.py 只包含:

print "hello"
while True:
    pass

go 程序在我运行时挂起并且不输出任何内容,但是如果我使用 os.Stdout 而不是 out 那么它会在它之前输出“hello”挂起。为什么两个 io.Writer 之间存在差异,如何解决?

一些更多的诊断信息:

  • 当循环从 inf_loop.py 中移除时,两个程序都会输出“hello”,正如预期的那样。
  • 当使用 yes 作为程序而不是 python 脚本并在 outstream.Write 中输出 len(p) 时,就会有输出,并且输出通常是 16384 或 32768。这向我表明这是一个缓冲问题,正如我最初预期的那样,但我仍然不明白为什么 outstream 结构被缓冲阻塞但是 os.Stdout 不是。一种可能是该行为是 execio.Writer 直接传递给 os.StartProcess 的方式的结果,如果它是 os.File(详见 source),否则它会在进程和 io.Writer 之间创建一个 os.Pipe(),并且此管道可能导致缓冲。但是,os.Pipe() 的操作和可能的缓冲级别太低,我无法研究。

最佳答案

Python 默认缓冲标准输出。试试这个程序:

import sys
print "hello"
sys.stdout.flush()
while True:
    pass

或者使用无缓冲的 stdout 和 stderr 运行 Python:

cmd := exec.Command("python", "-u", "foo.py")

注意 -u 标志。

当使用 cmd.Stout = os.Stdout 时,您会看到不同的结果,因为当 stdout 是终端时,Python 使用行缓冲。

关于go - 从 `exec.Cmd` 中获取 "real-time"的输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31015754/

相关文章:

c - C中访问并运行/usr/bin程序

java - 关于 .jar 文件和通过 PHP 运行 java 程序的问题

bash - 如何将 STDERR 重定向到 STDOUT,但忽略原始 STDOUT?

perl - 将标准输入/标准输出从执行的进程重定向到 Perl 中的管道

perl - 我可以从 perl 中的进程捕获 STDOUT 写入事件吗?

go - 为什么 encoding/json 将 slice 编码为 base64?

go - 导入路径差使用 "build"和 "tool compile"

go pprof 在不同的平台上不起作用

php - exec 在 window server 2008 php 上不起作用

type-conversion - 如何将 int[] 转换为 uint8[]