PEP 3145 – subprocess.Popen 的异步 I/O
- 作者:
- Eric Pruitt, Charles R. McCreary, Josiah Carlson
- 状态:
- 已撤回
- 类型:
- 标准跟踪
- 创建日期:
- 2009年8月4日
- Python 版本:
- 3.2
- 发布历史:
摘要
目前,subprocess.Popen 的实现容易在等待子进程数据时发生死锁和父 Python 脚本阻塞。本 PEP 提议使 subprocess.Popen 更加异步,以缓解这些问题。
PEP 延期
本 PEP 所涵盖概念的进一步探讨已推迟,至少要等到 PEP 3156 解决之后。
PEP 撤回
这个问题可以在 bug 跟踪器中解决。一个具体的提案已附在 [11]。
动机
搜索“python asynchronous subprocess”会找到大量关于人们希望执行子进程并与其进行通信的描述,即只读取可用数据,而不是阻塞等待程序生成数据 [1] [2] [3]。 subprocess 模块的当前行为是,当用户通过 stdin、stderr 和 stdout 文件对象发送或接收数据时,死锁很常见并且有记录 [4] [5]。虽然 `communicate` 可以用来缓解一些缓冲问题,但在尝试从子进程读取数据时,当没有可用数据时,它仍然会导致父进程阻塞。
基本原理
在 subprocess.Popen 中,存在对异步、非阻塞功能的文档化需求 [6] [7] [2] [3]。包含此代码将提高 Python 标准库的实用性,可用于基于 Unix 和 Windows 的 Python 版本。Python 中几乎所有的 I/O 对象都有某种文件类包装器。套接字已经像这样工作,对于字符串有 StringIO。通过使用 subprocess.Popen.stderr、stdout 和 stdin 文件类对象的附加方法,Popen 可以被使作像一个文件。但是,在使用这些选项的读写方法时,您无法获得异步 I/O 的好处。在提出的解决方案中,包装器封装了异步方法以模拟文件对象。
参考实现
我一直在维护一个 Google Code 存储库,其中包含我所有的更改,包括测试和文档 [9],以及一个博客,详细说明了我在开发过程中遇到的问题 [10]。
我一直在努力在 subprocess 模块中实现非阻塞异步 I/O,以及为 subprocess.Popen 实现一个包装类,该类使得执行的进程可以通过复制文件对象拥有的所有方法和属性来替代文件。
subprocess.Popen 类中添加了两个基本函数:Popen.send 和 Popen._recv,每个函数都有两个独立实现,一个用于 Windows,一个用于基于 Unix 的系统。Windows 实现使用 ctypes 来访问 kernel 32 DLL 中以异步方式控制管道所需的功能。在基于 Unix 的系统上,Python 文件控制接口起着相同的目的。 Popen.send 和 Popen._recv 的不同实现具有相同的参数,以便使用这些函数的代码可以在多个平台上工作。
在调用 Popen._recv 函数时,它需要将管道名称作为参数传递,因此存在 Popen.recv 函数,该函数默认选择 stdout 作为 Popen._recv 的管道。Popen.recv_err 默认选择 stderr 作为管道。Popen.recv 和 Popen.recv_err 比 Popen._recv('stdout' ...) 和 Popen._recv('stderr' ...) 分别更容易阅读和理解。
由于 Popen._recv 函数在返回值之前不等待数据生成,因此它可能返回空字节。Popen.asyncread 通过在给定的时间间隔内返回所有读取到的数据来处理此问题。
ProcessIOWrapper 类使用 asyncread 和 asyncwrite 函数,允许进程像文件一样工作,从而避免了在使用 subprocess.Popen 调用产生的 stdout 和 stdin 文件对象时可能出现的阻塞问题。
参考资料
[8] subprocess.rst - subprocdev - Project Hosting on Google Code https://web.archive.org/web/20130306074135/http://code.google.com/p/subprocdev/source/browse/doc/subprocess.rst?spec=svn2c925e935cad0166d5da85e37c742d8e7f609de5&r=2c925e935cad0166d5da85e37c742d8e7f609de5
版权
本 P.E.P. 采用开放出版许可;http://www.opencontent.org/openpub/。
来源:https://github.com/python/peps/blob/main/peps/pep-3145.rst