繁体   English   中英

如何从子进程中获取“实时”信息.Popen在python(2.5)中

[英]How do I get 'real-time' information back from a subprocess.Popen in python (2.5)

我想以下列方式使用子进程模块:

  1. 创建一个可能需要很长时间才能执行的新流程。
  2. 捕获stdout (或stderr ,或可能两者,一起或分开)
  3. 处理来自子进程的数据可能在接收的每一行上触发事件(在wxPython中说)或者只是暂时将它们打印出来。

我已经用Popen创建了进程,但是如果我使用communication(),那么一旦进程终止,数据就会立刻出现在我面前。

如果我创建一个单独的线程来执行myprocess.stdout的阻塞readline() (使用stdout = subprocess.PIPE myprocess.stdout ),我也不会使用此方法获得任何行,直到进程终止。 (无论我设置为bufsize)

有没有办法解决这个不可怕的问题,并且在多个平台上运行良好?

更新代码似乎无法正常工作(无论如何在Windows上)

class ThreadWorker(threading.Thread):
    def __init__(self, callable, *args, **kwargs):
        super(ThreadWorker, self).__init__()
        self.callable = callable
        self.args = args
        self.kwargs = kwargs
        self.setDaemon(True)

    def run(self):
        try:
            self.callable(*self.args, **self.kwargs)
        except wx.PyDeadObjectError:
            pass
        except Exception, e:
            print e



if __name__ == "__main__":
    import os
    from subprocess import Popen, PIPE

    def worker(pipe):
        while True:
            line = pipe.readline()
            if line == '': break
            else: print line

    proc = Popen("python subprocess_test.py", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)

    stdout_worker = ThreadWorker(worker, proc.stdout)
    stderr_worker = ThreadWorker(worker, proc.stderr)
    stdout_worker.start()
    stderr_worker.start()
    while True: pass

stdout将被缓冲 - 因此在填充缓冲区或子进程退出之前,您将无法获得任何内容。

您可以尝试从子进程刷新stdout ,或使用stderr,或在非缓冲模式下更改stdout。

这对我有用:

cmd = ["./tester_script.bash"]
p = subprocess.Popen( cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
while p.poll() is None:
    out = p.stdout.readline()
    do_something_with( out, err )

在您的情况下,您可以尝试将对子流程的引用传递给您的工作线程,并在线程内部进行轮询。 我不知道当两个线程轮询(并与之交互)同一个子进程时它会如何表现,但它可能会起作用。

另请注意, while p.poll() is None:按原样使用。 没有取代它while not p.poll()在蟒蛇0 (该返回码成功终止),也被认为是False

听起来问题可能是子进程使用缓冲输出 - 如果创建了相对少量的输出,则可以缓冲它直到子进程退出。 一些背景可以在这里找到:

这似乎是一个众所周知的Python限制,请参阅PEP 3145和其他人。

我也遇到过这个问题。 出现此问题的原因是您也尝试读取stderr。 如果没有错误,那么尝试从stderr读取将阻止。

在Windows上,没有简单的方法来轮询()文件描述符(只有Winsock套接字)。

因此,解决方案不是尝试从stderr读取。

一次阅读一个字符: http//blog.thelinuxkid.com/2013/06/get-python-subprocess-output-without.html

import contextlib
import subprocess

# Unix, Windows and old Macintosh end-of-line
newlines = ['\n', '\r\n', '\r']
def unbuffered(proc, stream='stdout'):
    stream = getattr(proc, stream)
    with contextlib.closing(stream):
        while True:
            out = []
            last = stream.read(1)
            # Don't loop forever
            if last == '' and proc.poll() is not None:
                break
            while last not in newlines:
                # Don't loop forever
                if last == '' and proc.poll() is not None:
                    break
                out.append(last)
                last = stream.read(1)
            out = ''.join(out)
            yield out

def example():
    cmd = ['ls', '-l', '/']
    proc = subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        # Make all end-of-lines '\n'
        universal_newlines=True,
    )
    for line in unbuffered(proc):
        print line

example()

使用带有非阻塞读取线的pexpect [ http://www.noah.org/wiki/Pexpect]将解决此问题。 它源于管道缓冲的事实,因此您的应用程序的输出被管道缓冲,因此在缓冲区填充或进程终止之前,您无法获得该输出。

使用subprocess.Popen,我可以运行我的一个C#项目的.exe并将输出重定向到我的Python文件。 我现在能够将所有输出到C#控制台的信息(使用Console.WriteLine()print()到Python控制台。

Python代码:

from subprocess import Popen, PIPE, STDOUT

p = Popen('ConsoleDataImporter.exe', stdout = PIPE, stderr = STDOUT, shell = True)

while True:
    line = p.stdout.readline()
    print(line)
    if not line:
        break

这将在我的.NET项目创建时逐行获取控制台输出,并在项目终止时突破封闭的while循环。 我想这也适用于两个python文件。

我已经使用了pexpect模块,它似乎工作正常。 http://sourceforge.net/projects/pexpect/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM