5

pty用来读取非阻塞进程的标准输出,如下所示:

import os
import pty
import subprocess

master, slave = pty.openpty()

p = subprocess.Popen(cmd, stdout = slave)

stdout = os.fdopen(master)
while True:
    if p.poll() != None:
        break

    print stdout.readline() 

stdout.close()

一切正常,除了while-loop偶尔阻塞。这是因为该行print stdout.readline()正在等待从中读取某些内容stdout。但是如果程序已经终止,我上面的小脚本将永远挂起。

我的问题是:有没有办法窥视stdout对象并检查是否有数据可供读取?如果不是这种情况,它应该继续执行while-loop它会发现进程实际上已经终止并中断循环的地方。

4

2 回答 2

11

是的,使用select 模块的 poll

import select
q = select.poll()
q.register(stdout,select.POLLIN)

并在同时使用:

l = q.poll(0)
if not l:
    pass # no input
else:
    pass # there is some input
于 2011-06-27T08:50:05.393 回答
2

select.poll ()答案非常简洁,但不适用于 Windows。以下解决方案是一种替代方案。它不允许您查看标准输出,但提供了 readline() 的非阻塞替代方案,并且基于此答案

from subprocess import Popen, PIPE
from threading import Thread
def process_output(myprocess): #output-consuming thread
    nextline = None
    buf = ''
    while True:
        #--- extract line using read(1)
        out = myprocess.stdout.read(1)
        if out == '' and myprocess.poll() != None: break
        if out != '':
            buf += out
            if out == '\n':
                nextline = buf
                buf = ''
        if not nextline: continue
        line = nextline
        nextline = None

        #--- do whatever you want with line here
        print 'Line is:', line
    myprocess.stdout.close()

myprocess = Popen('myprogram.exe', stdout=PIPE) #output-producing process
p1 = Thread(target=process_output, args=(myprocess,)) #output-consuming thread
p1.daemon = True
p1.start()

#--- do whatever here and then kill process and thread if needed
if myprocess.poll() == None: #kill process; will automatically stop thread
    myprocess.kill()
    myprocess.wait()
if p1 and p1.is_alive(): #wait for thread to finish
    p1.join()

这里提出了其他非阻塞读取的解决方案,但对我不起作用:

  1. 需要 readline 的解决方案(包括基于队列的解决方案)总是阻塞。很难(不可能?)杀死执行 readline 的线程。它仅在创建它的进程完成时被杀死,而不是在输出生成进程被杀死时。
  2. 正如 anonnn 所指出的,将低级 fcntl 与高级 readline 调用混合可能无法正常工作。
  3. 使用 select.poll() 很简洁,但根据 python 文档在 Windows 上不起作用。
  4. 对于此任务,使用第三方库似乎有点过分,并且会增加额外的依赖项。
于 2013-03-15T05:04:51.577 回答