简体   繁体   English

当子进程在Python中运行时,如何从子进程PIPE获取数据?

[英]How do I get data from a subprocess PIPE while the subprocess is running in Python?

I've got a program on Windows that calls a bunch of subprocesses, and displays the results in a GUI. 我在Windows上有一个调用大量子进程的程序,并在GUI中显示结果。 I'm using PyQt for the GUI, and the subprocess module to run the programs. 我正在使用PyQt作为GUI,并使用subprocess模块来运行程序。

I've got the following WorkerThread , that spawns a subthread for each shell command devoted to reading the process stdout and printing the results (later I'll wire it up to the GUI). 我有以下WorkerThread ,它为每个shell命令生成一个子线程,专门用于读取进程标准输出并打印结果(稍后我将它连接到GUI)。

This all works. 这一切都有效。 Except proc.stdout.read(1) never returns until after the subprocess has completed. proc.stdout.read(1) 永远不会返回,直到子进程完成之后。 This is a big problem, since some of these subprocesses can take 15-20 minutes to run, and I need to display results as they're running. 这是一个很大的问题,因为其中一些子进程可能需要15-20分钟才能运行,我需要在运行时显示结果。

What do I need to do to get the pipe working while the subprocess is running? 在子进程运行时,我需要做什么才能使管道正常工作?

class WorkerThread(QtCore.QThread):
    def run(self):
        def sh(cmd, cwd = None):
            proc = subprocess.Popen(cmd,
                                    shell = True,
                                    stdout = subprocess.PIPE,
                                    stderr = subprocess.STDOUT,
                                    stdin = subprocess.PIPE,
                                    cwd = cwd,
                                    env = os.environ)

            proc.stdin.close()

            class ReadStdOutThread(QtCore.QThread):
                def run(_self):
                    s = ''
                    while True:
                        if self.request_exit: return

                        b = proc.stdout.read(1)
                        if b == '\n':
                            print s
                            s = ''
                            continue

                        if b:
                            s += b
                            continue

                        if s: print s
                        return

            thread = ReadStdOutThread()
            thread.start()

            retcode = proc.wait()
            if retcode:
                raise subprocess.CalledProcessError(retcode, cmd)

            return 0

FWIW: I rewrote the whole thing using QProcess , and I see the exact same problem. FWIW:我用QProcess重写了整个事情,我看到了完全相同的问题。 The stdout receives no data, until the underlying process has returned. 在基础进程返回之前, stdout接收任何数据。 Then I get everything all at once. 然后我立刻得到了所有的东西。

If you know how long will be the the lines of command's output you can poll on the stdout PIPE of the process. 如果您知道命令输出行的长度,您可以在进程的stdout PIPE上进行轮询。

An example of what I mean: 我的意思的一个例子:

import select
import subprocess
import threading
import os

# Some time consuming command.
command = 'while [ 1 ]; do sleep 1; echo "Testing"; done'

# A worker thread, not as complex as yours, just to show my point.
class Worker(threading.Thread):

    def __init__(self):
        super(Worker, self).__init__()
        self.proc = subprocess.Popen(
            command, shell=True, 
            stdout=subprocess.PIPE, 
            stdin=subprocess.PIPE, stderr=subprocess.STDOUT
        )

    def run(self):
        self.proc.communicate()


    def get_proc(self):
        # The proc is needed for ask him for his
        # output file descriptor later.
        return self.proc


if __name__ == '__main__':
    w = Worker()
    w.start()

    proc = w.get_proc()

    pollin = select.poll()

    pollin.register(proc.stdout, select.POLLIN)


    while ( 1 ):
        events = pollin.poll()
        for fd, event in events:
             if event == select.POLLIN:
                 # This is the main issue of my idea,
                 # if you don't know the length of lines
                 # that process ouput, this is a problem.
                 # I put 7 since I know the word "Testing" have
                 # 7 characters.
                 print os.read(fd, 7)

Maybe this is not exactly what you're looking for, but I think it give you a pretty good idea of what to do to solve your problem. 也许这不是您正在寻找的,但我认为它可以让您很好地了解如何解决您的问题。

EDIT : I think I've just found what you need Streaming stdout from a Python subprocess in Python . 编辑 :我想我刚从Python中的Python子进程中找到了你需要的Streaming stdout

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

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