0

我有一个 Python 程序,它通过subprocess.Popen. 第一个应该向控制台输出一些文本(仅供参考),并将一些文本写入它产生的第二个程序。然后,它应该等待第二个程序响应(read()来自它),并打印该响应。

第二个应该听第一个的输入(通过raw_input()),然后print给第一个发短信。

为了了解到底发生了什么,我在第二次延迟了 5 秒,结果让我有点吃惊。

这是代码:

import subprocess

print "1st starting."

app = subprocess.Popen("name", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) #<--- B

print "Writing something to app's STDIN..."
app.stdin.write(some_text)

print "Reading something from my STDIN..." #<--- A
result = app.stdout.read()

print "Result:"
print result

对于第二个:

import time

print "app invoked."

print "Waiting for text from STDIN..."
text = raw_input()

#process(text)
time.sleep(5)

print "magic"

当我运行这段代码时,它在 A 点暂停,因为那是最后一个控制台输出。

5 秒后,该"Result:\n"行将被输出,第二个程序print编辑的所有内容都将显示在控制台中。

为什么第一个程序在读取第二个程序的标准输出时会暂停?在读取其输出之前是否必须等待其子进程终止?如何更改它以便我可以在程序之间传递消息?

我正在运行 Debian Linux 7.0。

4

2 回答 2

1

答案不在于任何与 subprocess 模块相关的魔法,而在于read()Python 对象上的方法的典型行为。

如果你运行这个:

import subprocess
p = subprocess.Popen(['ls'], stdout=subprocess.PIPE)
help(p.stdout.read)

你会看到这个:

读(...)

read([size]) -> read at most size bytes, returned as a string.

If the size argument is negative or omitted, read until EOF is reached.
Notice that when in non-blocking mode, less data than what was requested
may be returned, even if no size parameter was given.

(结尾)

同样的事情适用于所有类似文件的对象。这很简单:read()不带参数调用会消耗缓冲区,直到遇到错误(通常是 EOF)。

EOF直到:

  • 子进程调用 sys.stdout.close(),或
  • 子进程退出,Python 运行时和/或 OS 内核清理其文件描述符

注意它os.read有不同的行为——更像是 C 中典型的缓冲 I/O。内置的 Python 帮助功能是无用的,但如果你在任何 UNIXy 系统上,你应该能够运行man 3 read;Python 的行为或多或少与那里的行为相匹配。

一句警告

上面的程序很好,但是这样的模式有时会导致死锁。subprocess 模块的文档在记录 Popen.wait() 的地方警告了这一点:

警告

这将在使用 stdout=PIPE 和/或 stderr=PIPE 时发生死锁,并且子进程会向管道生成足够的输出,从而阻塞等待 OS 管道缓冲区接受更多数据。使用communicate() 来避免这种情况。

如果您在与子进程进行双向通信时不小心,则可能会遇到类似的情况,具体取决于子进程正在做什么。

编辑

顺便说一句,这个页面涵盖了带有 EOF 的管道的行为:

如果所有引用管道写入端的文件描述符都已关闭,则尝试从管道读取(2)将看到文件结束(读取(2)将返回 0)。

编辑 2

正如 Lennart 上面提到的,如果您想要真正的双向通信,超越一次写入一次读取,您还需要注意缓冲。如果您阅读本文,您会对此有所了解,但您应该知道,缓冲 IO 在基于 UNIX 的系统中几乎总是这样工作的——这不是 Python 的怪癖。运行man stdio.h以获取更多信息。

于 2013-04-11T11:26:55.100 回答
1

您要求程序 1 从程序 2 读取输入。并且您在程序 2 输出任何内容之前将其暂停五秒钟。显然,程序 1 需要等待那五秒钟。所以发生的事情是完全可以预料的。

在读取其输出之前是否必须等待其子进程终止?

在某种程度上,是的,因为输入和输出是缓冲的,所以即使你将延迟移到打印也会发生同样的情况。

raw_input()无论如何,都会等待换行。

于 2013-04-11T10:53:10.213 回答