从“exec.Cmd”中获取“实时”

时间:2015-06-24 00:38:36

标签: 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脚本并在len(p)中输出outstream.Write时,会有输出,输出通常是16384或32768.这向我表明这是一个缓冲问题,正如我最初的预料,但我仍然不明白为什么outstream结构被缓冲阻止但os.Stdout不是。一种可能性是,行为是exec io.Writer如果是os.StartProcess直接传递给os.File的方式的结果(有关详细信息,请参阅source ),否则它会在进程和os.Pipe()之间创建io.Writer,并且此管道可能会导致缓冲。但是,os.Pipe()的操作和可能的缓冲对我来说太低了,无法进行调查。

1 个答案:

答案 0 :(得分:3)

默认情况下Python缓冲stdout。试试这个程序:

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使用行缓冲。