17.5. popen2 — 具有可访问 I/O 流的子进程 — Python 文档

来自菜鸟教程
Python/docs/2.7/library/popen2
跳转至:导航、​搜索

17.5. popen2 — 具有可访问 I/O 流的子进程

自 2.6 版起已弃用:此模块已过时。 使用 子进程 模块。 特别检查 用子进程模块 部分替换旧函数。


该模块允许您在 Unix 和 Windows 下生成进程并连接到它们的输入/输出/错误管道并获取它们的返回代码。

subprocess 模块为生成新进程和检索其结果提供了更强大的工具。 使用 subprocess 模块比使用 popen2 模块更可取。

该模块提供的主要接口是三个工厂函数。 对于其中的每一个,如果指定了 bufsize,则它指定了 I/O 管道的缓冲区大小。 mode,如果提供,应该是字符串 'b''t'; 在 Windows 上,这需要确定文件对象应该以二进制还是文本模式打开。 mode 的默认值为 't'

在 Unix 上,cmd 可能是一个序列,在这种情况下,参数将直接传递给程序而无需 shell 干预(如 os.spawnv())。 如果 cmd 是一个字符串,它将被传递给 shell(与 os.system() 一样)。

检索子进程返回码的唯一方法是使用 Popen3Popen4 类上的 poll()wait() 方法; 这些仅在 Unix 上可用。 使用 popen2()popen3()popen4() 函数或 os 中的等效函数时,此信息不可用 模块。 (请注意,os 模块函数返回的元组与 popen2 模块返回的元组顺序不同。)

popen2.popen2(cmd[, bufsize[, mode]])
执行 cmd 作为子进程。 返回文件对象 (child_stdout, child_stdin)
popen2.popen3(cmd[, bufsize[, mode]])
执行 cmd 作为子进程。 返回文件对象 (child_stdout, child_stdin, child_stderr)
popen2.popen4(cmd[, bufsize[, mode]])

执行 cmd 作为子进程。 返回文件对象 (child_stdout_and_stderr, child_stdin)

2.0 版中的新功能。

在 Unix 上,还可以使用定义工厂函数返回的对象的类。 这些不用于 Windows 实现,并且在该平台上不可用。

class popen2.Popen3(cmd[, capturestderr[, bufsize]])

这个类代表一个子进程。 通常,Popen3 实例是使用上述 popen2()popen3() 工厂函数创建的。

如果不使用帮助函数之一来创建 Popen3 对象,则参数 cmd 是要在子进程中执行的 shell 命令。 capturestderr 标志(如果为真)指定对象应捕获子进程的标准错误输出。 默认值为假。 如果指定了 bufsize 参数,则它指定进出子进程的 I/O 缓冲区的大小。

class popen2.Popen4(cmd[, bufsize])

类似于 Popen3,但总是将标准错误捕获到与标准输出相同的文件对象中。 这些通常是使用 popen4() 创建的。

2.0 版中的新功能。

17.5.1. Popen3 和 Popen4 对象

Popen3Popen4 类的实例具有以下方法:

Popen3.poll()
如果子进程尚未完成,则返回 -1,否则返回其状态代码(参见 wait())。
Popen3.wait()
等待并返回子进程的状态码。 状态代码对进程的返回代码和有关它是使用 exit() 系统调用退出还是由于信号而死亡的信息进行编码。 os模块中定义了帮助解释状态码的函数; 有关 W*() 函数系列的信息,请参阅 进程管理 部分。

还可以使用以下属性:

Popen3.fromchild
提供子进程输出的文件对象。 对于 Popen4 实例,这将提供标准输出和标准错误流。
Popen3.tochild
为子进程提供输入的文件对象。
Popen3.childerr
如果构造函数的 capturestderr 为真,则提供子进程的错误输出的文件对象,否则为 None。 对于 Popen4 实例,这将始终是 None
Popen3.pid
子进程的进程 ID。


17.5.2. 流量控制问题

任何时候处理任何形式的进程间通信时,都需要仔细考虑控制流。 对于此模块(或 os 模块等效项)提供的文件对象,情况仍然如此。

在父进程从子进程的标准输出中读取大量数据的子进程读取输出时,可能会发生死锁。 其他读取和写入组合也可能发生类似情况。 主要因素是一个进程以阻塞方式写入了超过 _PC_PIPE_BUF 个字节,而另一个进程正在以阻塞方式从第一个进程读取。

有几种方法可以处理这种情况。

在许多情况下,最简单的应用程序更改将是在父进程中遵循此模型:

import popen2

r, w, e = popen2.popen3('python slave.py')
e.readlines()
r.readlines()
r.close()
e.close()
w.close()

在孩子中使用这样的代码:

import os
import sys

# note that each of these print statements
# writes a single long string

print >>sys.stderr, 400 * 'this is a test\n'
os.close(sys.stderr.fileno())
print >>sys.stdout, 400 * 'this is another test\n'

特别要注意的是,写入所有数据后必须关闭 sys.stderr,否则 readlines() 将不会返回。 另请注意,必须使用 os.close(),因为 sys.stderr.close() 不会关闭 stderr(否则分配给 sys.stderr 将默默关闭它,所以不能打印更多的错误)。

需要支持更通用方法的应用程序应将管道上的 I/O 与其 select() 循环集成,或使用单独的线程读取由 popen*() 函数提供的每个文件或 Popen* 类被使用。

也可以看看

模块 子进程
用于生成和管理子进程的模块。