【问题标题】:Intercepting stdout of a subprocess while it is running在运行时拦截子进程的标准输出
【发布时间】:2010-10-06 08:18:33
【问题描述】:

如果这是我的子流程:

import time, sys
for i in range(200):
    sys.stdout.write( 'reading %i\n'%i )
    time.sleep(.02)

这是控制和修改子进程输出的脚本:

import subprocess, time, sys

print 'starting'
    
proc = subprocess.Popen(
    'c:/test_apps/testcr.py',
    shell=True,
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE  )

print 'process created'

while True:
    #next_line = proc.communicate()[0]
    next_line = proc.stdout.readline()
    if next_line == '' and proc.poll() != None:
        break
    sys.stdout.write(next_line)
    sys.stdout.flush()
    
print 'done'

为什么readlinecommunicate 一直等到进程完成运行?有没有一种简单的方法来实时传递(和修改)子进程的标准输出?

我使用的是 Windows XP。

【问题讨论】:

标签: python process subprocess stdout popen


【解决方案1】:

正如查尔斯已经提到的,问题在于缓冲。我在为 SNMPd 编写一些模块时遇到了类似的问题,并通过将 stdout 替换为自动刷新版本来解决它。

我使用了以下代码,灵感来自 ActiveState 上的一些帖子:

class FlushFile(object):
    """Write-only flushing wrapper for file-type objects."""
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()

# Replace stdout with an automatically flushing version
sys.stdout = FlushFile(sys.__stdout__)

【讨论】:

  • 我看不出这与在每个 sys.stdout.readline() 之后调用 sys.stdout.flush() 有何不同,这就是我所做的。我还尝试为子进程设置 bufsize=0。
  • 子进程需要flush,而不是父进程。
  • 是的,在这个例子中子进程也是一个python脚本。所以替换子进程中的stdout。在父进程中调用 sys.stdout.flush() 没有任何作用。
  • 好的。我看到我在那里做了什么。当然,这个子进程只是一个示例。我的真实过程是一大块已编译的 FORTRAN,我无法访问它的源代码。在这种情况下,我只需要希望孩子没有缓冲输出?那么 subprocess.Popen 的 bufsize 是做什么的呢?
  • 据我所知,决定输出缓冲区大小的是应用程序代码。我不认为你可以在外部做任何事情,除非它是动态链接的并且你预加载了一个替换系统调用的库。但这是一个巨大的黑客,超出了这个问题的范围:)
【解决方案2】:

进程输出被缓冲。在更多的 UNIXy 操作系统(或 Cygwin)上,pexpect 模块可用,它背诵了所有必要的咒语以避免与缓冲相关的问题。但是,这些咒语需要有效的pty module,这在本机(非 cygwin)win32 Python 版本上不可用。

在您控制子进程的示例情况下,您可以让它在必要时调用sys.stdout.flush() - 但对于任意子进程,该选项不可用。

另请参阅 pexpect 常见问题解答中的 the question "Why not just use a pipe (popen())?"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 2021-08-27
    • 2015-02-04
    • 2021-06-24
    • 2017-07-22
    • 2018-12-06
    • 1970-01-01
    相关资源
    最近更新 更多