【问题标题】:How do I get data from a subprocess PIPE while the subprocess is running in Python?当子进程在 Python 中运行时,如何从子进程 PIPE 获取数据?
【发布时间】:2013-12-19 15:16:14
【问题描述】:

我在 Windows 上有一个程序,它调用一堆子进程,并在 GUI 中显示结果。我将 PyQt 用于 GUI,并使用 subprocess 模块来运行程序。

我有以下WorkerThread,它为每个 shell 命令生成一个子线程,专门用于读取进程 stdout 并打印结果(稍后我会将它连接到 GUI) .

这一切都有效。 除了proc.stdout.read(1)从不在子流程完成之前返回。这是一个大问题,因为其中一些子流程可能需要 15-20 分钟才能运行,而且我需要在它们运行时显示结果。

在子进程运行时我需要做什么才能使管道正常工作?

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:我使用QProcess 重写了整个内容,我看到了完全相同的问题。 stdout 不接收任何数据,直到底层进程返回。然后我一下子就搞定了。

【问题讨论】:

    标签: python multithreading pyqt subprocess qthread


    【解决方案1】:

    如果您知道命令输出的行数有多长,您可以在进程的 stdout PIPE 上进行轮询。

    我的意思的一个例子:

    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)
    

    也许这不是您想要的,但我认为它可以让您很好地了解如何解决您的问题。

    编辑:我想我刚刚找到了你需要的东西Streaming stdout from a Python subprocess in Python

    【讨论】:

    • 不知道输出多久。
    • @ChrisB。我刚刚添加了一个示例的链接,它可能是您正在寻找的。​​span>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 2014-03-30
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多