子进程 — Python 文档
子流程
本节介绍用于创建和管理子进程的高级 async/await asyncio API。
以下是 asyncio 如何运行 shell 命令并获取其结果的示例:
import asyncio
async def run(cmd):
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(f'[{cmd!r} exited with {proc.returncode}]')
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
asyncio.run(run('ls /zzz'))
将打印:
['ls /zzz' exited with 1]
[stderr]
ls: /zzz: No such file or directory
因为所有 asyncio 子进程函数都是异步的,并且 asyncio 提供了许多工具来处理这些函数,所以很容易并行执行和监视多个子进程。 修改上面的例子来同时运行几个命令确实很简单:
async def main():
await asyncio.gather(
run('ls /zzz'),
run('sleep 1; echo "hello"'))
asyncio.run(main())
另请参阅 示例 小节。
创建子流程
重要的
应用程序有责任确保正确引用所有空格和特殊字符以避免 shell 注入 漏洞。 shlex.quote() 函数可用于正确转义将用于构造 shell 命令的字符串中的空格和特殊 shell 字符。
笔记
Windows 上的默认异步事件循环实现不支持子进程。 如果使用 ProactorEventLoop,则子进程可用于 Windows。 有关详细信息,请参阅 Windows 上的子进程支持 [X37X]。
常数
- asyncio.subprocess.PIPE
可以传递给 stdin、stdout 或 stderr 参数。
如果将 PIPE 传递给 stdin 参数,则 Process.stdin 属性将指向 StreamWriter 实例。
如果将 PIPE 传递给 stdout 或 stderr 参数,则 Process.stdout 和 Process.stderr 属性将指向 StreamReader 实例。
- asyncio.subprocess.STDOUT
- 可用作 stderr 参数并指示标准错误应重定向到标准输出的特殊值。
- asyncio.subprocess.DEVNULL
- 可用作进程创建函数的 stdin、stdout 或 stderr 参数的特殊值。 它表示特殊文件 os.devnull 将用于相应的子流程流。
与子进程交互
create_subprocess_exec()
和 create_subprocess_shell()
函数都返回 Process 类的实例。 Process 是一个高级包装器,允许与子进程通信并观察它们的完成。
- class asyncio.subprocess.Process
包装由
create_subprocess_exec()
和create_subprocess_shell()
函数创建的操作系统进程的对象。此类旨在具有与 subprocess.Popen 类类似的 API,但有一些显着差异:
与 Popen 不同,Process 实例没有与 poll() 方法等效的方法;
communicate()
和wait()
方法没有 timeout 参数:使用wait_for()
函数;Process.wait()
方法是异步的,而 subprocess.Popen.wait() 方法是作为阻塞忙循环实现的;不支持 universal_newlines 参数。
此类是 不是线程安全的 。
另请参阅 子进程和线程 部分。
- send_signal(signal)
向子进程发送信号signal。
笔记
在 Windows 上,
SIGTERM
是 terminate() 的别名。CTRL_C_EVENT
和CTRL_BREAK_EVENT
可以发送到以 creationflags 参数启动的进程,该参数包括CREATE_NEW_PROCESS_GROUP
。
- terminate()
停止子进程。
在 POSIX 系统上,此方法将 signal.SIGTERM 发送到子进程。
在 Windows 上,调用 Win32 API 函数
TerminateProcess()
来停止子进程。
- kill()
杀了孩子。
在 POSIX 系统上,此方法将
SIGKILL
发送到子进程。在 Windows 上,此方法是 terminate() 的别名。
- stdin
标准输入流 (StreamWriter) 或
None
如果进程是用stdin=None
创建的。
- stdout
标准输出流 (StreamReader) 或
None
如果进程是用stdout=None
创建的。
- stderr
标准错误流 (StreamReader) 或
None
如果进程是用stderr=None
创建的。
警告
使用
communicate()
方法而不是 process.stdin.write()、await process.stdout.read() 或 await process.stderr.read[ X138X]。 这避免了由于流暂停读取或写入并阻塞子进程而导致的死锁。- pid
进程标识号 (PID)。
请注意,对于由
create_subprocess_shell()
函数创建的进程,该属性是生成的 shell 的 PID。
- returncode
退出时返回进程的代码。
None
值表示进程尚未终止。负值
-N
表示子进程被信号N
(仅 POSIX)终止。
子进程和线程
标准的 asyncio 事件循环支持从不同线程运行子进程,但有一些限制:
- 事件循环必须在主线程中运行。
- 在从其他线程执行子进程之前,必须在主线程中实例化子观察者。 在主线程中调用get_child_watcher()函数来实例化子观察者。
请注意,替代事件循环实现可能不具有上述限制; 请参考他们的文档。
例子
使用 Process 类控制子进程和使用 StreamReader 类从其标准输出中读取的示例。
子流程由 create_subprocess_exec()
函数创建:
import asyncio
import sys
async def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess; redirect the standard output
# into a pipe.
proc = await asyncio.create_subprocess_exec(
sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
# Read one line of output.
data = await proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit.
await proc.wait()
return line
if sys.platform == "win32":
asyncio.set_event_loop_policy(
asyncio.WindowsProactorEventLoopPolicy())
date = asyncio.run(get_date())
print(f"Current date: {date}")
另请参阅使用低级 API 编写的 相同示例 。