我有一个程序,它在线程中创建一个子进程,以便线程可以不断检查特定的输出条件(来自 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 上运行)上尝试这个,并且也尝试过select.poll()
and select.epoll()
基于 Python 2.6 的变体(在具有 2.6 内核的 Debian 上运行)。