Subproces.popen - 从机写入失败:管道损坏;中止

时间:2016-06-06 02:46:44

标签: python subprocess

TLDR:坚持这个https://code.google.com/archive/p/byte-unixbench/issues/1

尝试使用subprocess.popen()运行UnixBench,同时捕获输出并实时打印出来。

这是我提出的子程序:

def run_and_print(command, cwd=None, catch_stderr = False):
    if catch_stderr:
        err_pipe = subprocess.PIPE
    else:
        err_pipe = subprocess.STDOUT

    p = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=1, cwd=cwd, stderr=err_pipe)
    r = ''
    while True:
        if catch_stderr:
            out = p.stderr.read(1)
        else:
            out = p.stdout.read(1)
        if out == "" and p.poll() != None:
            break
        sys.stdout.write(out)
        sys.stdout.flush()
        r += out

    return r

除了UnixBench之外,它适用于所有目的。 Unixbench在一段时间后就死了:

unixbench = run_and_print(['./Run'])
  

...

     

1 x管道吞吐量1 2 3 4 5 6 7 8 9 10

     

1 x基于管道的上下文切换1 2 3 4

           

运行:"基于管道的上下文切换":从站写入失败:管道损坏;中止

谷歌并没有多大帮助。我得到的唯一有意义的结果是https://code.google.com/archive/p/byte-unixbench/issues/1并建议创建一个java应用程序的解决方案对我来说不起作用,因为我需要尽可能少地运行脚本。

我会感谢任何解决方案或解决方法。我正在测试的系统是Ubuntu 14.04.4 x64

1 个答案:

答案 0 :(得分:2)

该错误与'yes' reporting error with subprocess communicate()有关,restore_signals() is defined here使用SIGPIPE(或使用Python 3)在子进程中提供修复:reenable preexec_fn信号。

无关:如果catch_stderr为真且p.stderrp.stdout未完全同步,则您的代码可能会死锁。

否则catch_stderr无效(忽略缓冲):您的代码无论如何都会捕获stderr。你可以简化它:

#!/usr/bin/env python
from shutil import copyfileobj
from subprocess import Popen, PIPE, STDOUT

def run_and_print(command, cwd=None):
    p = Popen(command, stdout=PIPE, stderr=STDOUT, bufsize=-1, cwd=cwd,
              preexec_fn=restore_signals)
    with p.stdout:
        tee = Tee()
        copyfileobj(p.stdout, tee)        
    return p.wait(), tee.getvalue()

其中Tee()是一个类似文件的对象,写入两个地方:stdout和StringIO()

import sys
from io import BytesIO

class Tee:
   def __init__(self):
       self.file = BytesIO()
   def write(self, data):
       getattr(sys.stdout, 'buffer', sys.stdout).write(data)
       self.file.write(data)
   def getvalue(self):
       return self.file.getvalue()

其中copyfileobj()

如果要在命令打印时立即在屏幕上看到输出;您可以内联Teeuse os.read()run it using stdbuf or pass pseudo-tty instead of the pipe,以避免在将length写入stdout之前阅读完整的chunks = [] with p.stdout: for chunk in iter(lambda: os.read(p.stdout.fileno(), 1 << 13), b''): getattr(sys.stdout, 'buffer', sys.stdout).write(chunk) sys.stdout.flush() chunks.append(chunk) return p.wait(), b''.join(chunks)

public class Product
{
    public virtual ICollection<Product> RequiredProducts {get; set;}    
    ...
}

要在子进程中禁用内部块缓冲,您可以尝试https://developers.google.com/web/tools/chrome-devtools/iterate/inspect-styles/?hl=en