gpt4 book ai didi

python - 使用 Python 的选择模块检查是否有更多数据要从文件描述符中读取

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:19:54 27 4
gpt4 key购买 nike

我有一个在线程内创建子进程的程序,以便线程可以不断检查特定的输出条件(来自 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 中的所有数据都已处理。

我遇到的困难是,如果我的最后一个条件如上(如果没有准备好并且 proc.poll() 不是 None),那么线程永远不会退出,因为一旦 stdout 和stderr 的文件描述符被标记为就绪,它们永远不会变得未就绪(即使在从中读取了所有数据之后,read() 会挂起或 readline() 会返回一个空字符串)。

如果我将该条件更改为仅if proc.poll() is not None,则当程序退出时循环存在,我不能保证它看到了所有数据需要处理。

这是错误的方法,还是有一种方法可以可靠地确定您何时读取了所有将写入文件描述符的数据?或者这是一个特定于尝试从子进程的 stderr/stdout 读取的问题?

我一直在 Python 2.5(在 OS X 上运行)上尝试这个,还在 Python 上尝试了基于 select.poll()select.epoll() 的变体2.6(在具有 2.6 内核的 D​​ebian 上运行)。

最佳答案

select 模块适用于确定是否可以无阻塞地从管道中读取数据。

为确保您已读取所有数据,请使用更简单的条件 if proc.poll() is not None: break 并调用 rest = [pipe.read() for在循环之后通过管道输入 [p.stdout, p.stderr]]

子进程在关闭之前不太可能关闭其标准输出/标准错误,因此您可以为简单起见跳过处理 EOF 的逻辑。


不要直接调用 Thread.run(),而是使用 Thread.start()。您可能根本不需要此处的单独线程。

不要在select()之后调用p.stdout.readline(),它可能会阻塞,使用os.read(p.stdout. fileno(), limit) 代替。空字节串表示相应管道的 EOF。


作为替代或补充,您可以使用 fcntl 模块使管道成为非阻塞的:

import os
from fcntl import fcntl, F_GETFL, F_SETFL

def make_nonblocking(fd):
return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | os.O_NONBLOCK)

并在阅读时处理 io/os 错误。

关于python - 使用 Python 的选择模块检查是否有更多数据要从文件描述符中读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23677526/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com