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

从 2.6 版开始不推荐使用:该模块已淘汰。使用subprocess模块。尤其要检查用子流程模块替换旧Function部分。

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

subprocess模块提供了更强大的Function来生成新流程并检索其结果。使用subprocess模块比使用popen2模块更好。

此模块提供的主要接口是工厂Function的三个。对于每一个,如果指定* 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()Function或os模块中的等效Function时,此信息不可用。 (请注意,os模块的函数返回的 Tuples 的 Sequences 与popen2模块的返回 Tuples 的 Sequences 不同。)

  • popen2. popen2(* cmd * [,* bufsize * [,* mode *]])

    • 将* cmd *作为 subprocess 执行。返回文件对象(child_stdout, child_stdin)
  • popen2. popen3(* cmd * [,* bufsize * [,* mode *]])

    • 将* cmd *作为 subprocess 执行。返回文件对象(child_stdout, child_stdin, child_stderr)
  • popen2. popen4(* cmd * [,* bufsize * [,* mode *]])

    • 将* cmd *作为 subprocess 执行。返回文件对象(child_stdout_and_stderr, child_stdin)

2.0 版中的新Function。

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

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

如果未使用辅助函数之一创建Popen3对象,则参数* cmd *是要在子进程中执行的 shell 命令。 * capturestderr 标志,如果为 true,则指定对象应捕获子进程的标准错误输出。默认为 false。如果指定了 bufsize *参数,则它指定往返于子进程的 I/O 缓冲区的大小。

    • class * popen2. Popen4(* cmd * [,* bufsize *])
    • Popen3相似,但始终将标准错误捕获到与标准输出相同的文件对象中。这些通常是使用popen4()创建的。

2.0 版中的新Function。

17.5.1. Popen3 和 Popen4 对象

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

  • Popen3. poll ( )

    • 如果子进程尚未完成,则返回-1,否则返回其状态码(请参见wait())。
  • Popen3. wait ( )

    • await 并返回子进程的状态码。状态码既对进程的返回码进行编码,又对有关使用exit()系统调用退出还是由于 signal 死亡的信息进行编码。 os模块中定义了帮助解释状态代码的Function;有关W*()系列Function,请参见Process Management部分。

以下属性也可用:

  • Popen3. fromchild

    • 提供子进程输出的文件对象。对于Popen4实例,这将提供标准输出和标准错误流。
  • Popen3. tochild

    • 为子进程提供 Importing 的文件对象。
  • Popen3. childerr

    • 如果* capturestderr *对于构造函数为 true,则该文件对象提供子进程的错误输出,否则为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会以静默方式关闭stderr,因此无法再打印任何错误)。

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

See also

  • Module subprocess

  • 用于产生和 Management 子流程的模块。