【发布时间】:2014-05-15 11:56:51
【问题描述】:
我有一个在线程中创建子进程的程序,以便线程可以不断检查特定的输出条件(来自 stdout 或 stderr),并调用适当的回调,而程序的其余部分继续。这是该代码的精简版:
import select
import subprocess
import threading
def run_task():
command = ['python', 'a-script-that-outputs-lines.py']
proc = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
while True:
ready, _, _ = select.select((proc.stdout, proc.stderr), (), (), .1)
if proc.stdout in ready:
next_line_to_process = proc.stdout.readline()
# process the output
if proc.stderr in ready:
next_line_to_process = proc.stderr.readline()
# process the output
if not ready and proc.poll() is not None:
break
thread = threading.Thread(target = run_task)
thread.run()
它工作得相当好,但我希望线程在满足两个条件后退出:正在运行的子进程已完成,并且 stdout 和 stderr 中的所有数据都已处理。
我遇到的困难是,如果我的最后一个条件与上面一样(if not ready and proc.poll() is not None),那么线程永远不会退出,因为一旦 stdout 和 stderr 的文件描述符被标记为就绪,它们就永远不会变得未就绪(即使毕竟的数据已从中读取,read() 将挂起或readline() 将返回一个空字符串。
如果我将该条件更改为仅if proc.poll() is not None,则程序退出时循环存在,我不能保证它看到了所有需要处理的数据。
这只是错误的方法,还是有办法可靠地确定您何时读取了将写入文件描述符的所有数据?或者这是尝试从子进程的 stderr/stdout 读取时特有的问题?
我一直在 Python 2.5(在 OS X 上运行)上尝试这个,并且还在 Python 2.6 上尝试过基于 select.poll() 和 select.epoll() 的变体(在具有 2.6 内核的 Debian 上运行)。
【问题讨论】:
-
我目前正在运行的解决方案是测试
next_line_to_process是否为空(在调用readline()之后),如果它为空并且proc.poll()的输出为None,那么我从就绪列表中删除文件描述符并继续下一个(或查看是否该退出)。但我很想知道是否有其他解决方案。
标签: python linux select subprocess