子进程 — Python 文档

来自菜鸟教程
Python/docs/3.8/library/asyncio-subprocess
跳转至:导航、​搜索

子流程

源代码: :source:`Lib/asyncio/subprocess.py`, :source:`Lib/asyncio/base_subprocess.py`



本节介绍用于创建和管理子进程的高级 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())

另请参阅 示例 小节。

创建子流程

笔记

如果使用 ProactorEventLoop,则子进程可用于 Windows。 有关详细信息,请参阅 Windows 上的子进程支持 [X37X]。


也可以看看

asyncio 还具有以下 低级 API 来处理子进程:loop.subprocess_exec()、loop.subprocess_shell()、loop.connect_read_pipe()、loop.connect_write_pipe(),以及作为 子进程传输 和 子进程协议 。


常数

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 事件循环支持从不同线程运行子进程。

在 Windows 上,子进程仅由 ProactorEventLoop 提供(默认),SelectorEventLoop 没有子进程支持。

在 UNIX 上 child watchers 用于子进程完成等待,请参阅 Process Watchers 了解更多信息。

3.8 版更改: UNIX 切换到使用 ThreadedChildWatcher 来不受任何限制地从不同线程生成子进程。

生成具有 inactive 当前子观察者的子进程会引发 RuntimeError。


请注意,替代事件循环实现可能有自己的限制; 请参考他们的文档。

也可以看看

asyncio 部分中的 并发和多线程。


例子

使用 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

date = asyncio.run(get_date())
print(f"Current date: {date}")

另请参阅使用低级 API 编写的 相同示例 。