代码之家  ›  专栏  ›  技术社区  ›  Paul

在子进程运行时拦截其stdout

  •  25
  • Paul  · 技术社区  · 16 年前

    如果这是我的子流程:

    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 等待进程运行完毕?是否有一种简单的方法实时传递(和修改)子进程的stdout?

    我使用的是Windows XP。

    2 回复  |  直到 3 年前
        1
  •  16
  •   Kamil Kisiel    16 年前

    正如Charles已经提到的,问题在于缓冲。我在为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__)
    
        2
  •  8
  •   Charles Duffy    16 年前

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

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

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