在运行时拦截子进程的标准输出
Posted
技术标签:
【中文标题】在运行时拦截子进程的标准输出【英文标题】: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'
为什么readline
和communicate
一直等到进程完成运行?有没有一种简单的方法来实时传递(和修改)子进程的标准输出?
我使用的是 Windows XP。
【问题讨论】:
相关:How to flush output of Python print? 【参考方案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())?"。
【讨论】:
以上是关于在运行时拦截子进程的标准输出的主要内容,如果未能解决你的问题,请参考以下文章