Python:select() 不会发出来自管道的所有输入信号
我正在尝试使用 Python 加载外部命令行程序并通过管道与其进行通信。该程序通过标准输入获取文本输入,并按行生成文本输出到标准输出。通信应该使用 select() 进行异步。
问题是,并非程序的所有输出都在 select() 中发出信号。通常最后一两行没有信号。如果 select() 返回超时,并且我尝试从管道读取,无论如何 readline() 会立即返回从程序发送的行。请参阅下面的代码。
该程序不缓冲输出并以文本行发送所有输出。到目前为止,通过许多其他语言和环境中的管道连接到程序都运行良好。
我在 Mac OSX 10.6 上尝试过 Python 3.1 和 3.2。
import subprocess
import select
engine = subprocess.Popen("Engine", bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
engine.stdin.write(b"go\n")
engine.stdin.flush()
while True:
inputready,outputready,exceptready = select.select( [engine.stdout.fileno()] , [], [], 10.0)
if (inputready, outputready, exceptready) == ([], [], []):
print("trying to read from engine anyway...")
line = engine.stdout.readline()
print(line)
for s in inputready:
line = engine.stdout.readline()
print(line)
I am trying to load an external command line program with Python and communicate with it via pipes. The progam takes text input via stdin and produces text output in lines to stdout. Communication should be asynchronous using select().
The problem is, that not all output of the program is signalled in select(). Usually the last one or two lines are not signalled. If select() returns with a timeout and I am trying to read from the pipe anyway readline() returns immediately with the line sent from the program. See code below.
The program doesn't buffer the output and sends all output in text lines. Connecting to the program via pipes in many other languages and environments has worked fine so far.
I have tried Python 3.1 and 3.2 on Mac OSX 10.6.
import subprocess
import select
engine = subprocess.Popen("Engine", bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
engine.stdin.write(b"go\n")
engine.stdin.flush()
while True:
inputready,outputready,exceptready = select.select( [engine.stdout.fileno()] , [], [], 10.0)
if (inputready, outputready, exceptready) == ([], [], []):
print("trying to read from engine anyway...")
line = engine.stdout.readline()
print(line)
for s in inputready:
line = engine.stdout.readline()
print(line)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
请注意,
file.readlines([size])
在内部多次循环并调用read()
系统调用,尝试填充size
的内部缓冲区代码>.第一次调用 read() 将立即返回,因为 select() 指示 fd 可读。然而,第二次调用将阻塞,直到数据可用,这违背了使用 select 的目的。无论如何,在异步应用程序中使用 file.readlines([size]) 都是很棘手的。每次通过 select 时,您应该在每个 fd 上调用一次 os.read(fd, size) 。这将执行非阻塞读取,并允许您缓冲部分行,直到数据可用并明确检测到 EOF。
我修改了您的代码以说明如何使用 os.read 。它还从进程的
stderr
读取:Note that internally
file.readlines([size])
loops and invokes theread()
syscall more than once, attempting to fill an internal buffer ofsize
. The first call toread()
will immediately return, since select() indicated the fd was readable. However the 2nd call will block until data is available, which defeats the purpose of using select. In any case it is tricky to usefile.readlines([size])
in an asynchronous app.You should call
os.read(fd, size)
once on each fd for every pass through select. This performs a non-blocking read, and lets you buffer partial lines until data is available and detects EOF unambiguously.I modified your code to illustrate using
os.read
. It also reads from the process'stderr
: