Python:如何窥视pty对象以避免阻塞?

2024-09-27 07:28:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用pty读取如下进程的非阻塞stdout:

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,在那里它将发现进程实际上已经终止并中断循环。在


Tags: importmastercmdloopreadline进程osstdout
2条回答

select.poll()答案非常简洁,但在Windows上不起作用。下面的解决方案是另一种选择。它不允许您查看stdout,但提供了readline()的非阻塞替代方法,它基于this answer

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=(dcmpid,)) #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()

其他非阻塞读取的解决方案已经被提出here,但对我来说并不管用:

  1. 需要readline的解决方案(包括基于队列的解决方案)总是阻塞。这很难(不可能?)终止执行readline的线程。它只会在创建它的进程结束时被终止,而不会在输出生成过程被终止时终止。在
  2. 正如anonnn指出的那样,混合使用低级fcntl和高级readline调用可能无法正常工作。在
  3. 使用选择投票()很简洁,但根据python文档,它不适用于Windows。在
  4. 使用第三方库对于这个任务来说似乎有些过分,并且增加了额外的依赖性。在

是,使用select module's poll

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

在使用期间:

^{pr2}$

相关问题 更多 >

    热门问题