子过程

源代码: Lib/asyncio/subprocess.pyLib/asyncio/base_subprocess.py


本节介绍用于创建和管理子流程的高级异步/等待异步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())

也见 Examples 小节。

创建子流程

coroutine asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)

创建子流程。

这个 limit 参数设置缓冲区限制 StreamReader 封装纸 Process.stdoutProcess.stderr (如果 subprocess.PIPE 传递给 stdoutstderr 参数)。

返回A Process 实例。

参见以下文件: loop.subprocess_exec() 其他参数。

coroutine asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)

运行 cmd 外壳命令。

这个 limit 参数设置缓冲区限制 StreamReader 封装纸 Process.stdoutProcess.stderr (如果 subprocess.PIPE 传递给 stdoutstderr 参数)。

返回A Process 实例。

参见以下文件: loop.subprocess_shell() 其他参数。

重要

应用程序有责任确保所有空格和特殊字符都被适当地引用,以避免 shell injection 漏洞。这个 shlex.quote() 函数可用于正确转义将用于构造shell命令的字符串中的空白字符和特殊shell字符。

注解

子进程在以下情况下可用于Windows ProactorEventLoop 是使用的。看见 Subprocess Support on Windows 有关详细信息,请参阅。

参见

Asyncio还具有以下功能 low-level 用于子流程的API: loop.subprocess_exec()loop.subprocess_shell()loop.connect_read_pipe()loop.connect_write_pipe() 以及 Subprocess TransportsSubprocess Protocols .

常量

asyncio.subprocess.PIPE

可以传递给 stdinstdoutstderr 参数。

如果 PIPE 传递给 *stdin*参数 Process.stdin 属性将指向 StreamWriter 实例。

如果 PIPE 传递给 stdoutstderr 参数, Process.stdoutProcess.stderr 属性将指向 StreamReader 实例。

asyncio.subprocess.STDOUT

可以用作 stderr 参数并指示应将标准错误重定向到标准输出。

asyncio.subprocess.DEVNULL

可以用作 stdinstdoutstderr 进程创建函数的参数。表示特殊文件 os.devnull 将用于相应的子进程流。

与子流程交互

两个 create_subprocess_exec()create_subprocess_shell() 函数返回 过程 类。 过程 是一个高级封装器,允许与子流程通信并监视其完成情况。

class asyncio.subprocess.Process

封装由 create_subprocess_exec()create_subprocess_shell() 功能。

此类的设计目的是具有与 subprocess.Popen 但是有一些显著的区别:

这个类是 not thread safe .

也见 Subprocess and Threads 部分。

coroutine wait()

等待子进程终止。

设置并返回 returncode 属性。

注解

此方法在使用时可能死锁 stdout=PIPEstderr=PIPE 子进程生成的输出太多,以至于它会阻止等待OS管道缓冲区接受更多数据。使用 communicate() 方法在使用管道时避免这种情况。

coroutine communicate(input=None)

与流程交互:

  1. 发送数据到 stdin*(如果 *input 不是 None

  2. 从中读取数据 stdoutstderr ,直到达到EOF;

  3. 等待进程终止。

可选的 input 参数是数据 (bytes 对象)将发送到子进程。

返回元组 (stdout_data, stderr_data) .

如果任一 BrokenPipeErrorConnectionResetError 写入时引发异常 input 进入之内 stdin,忽略异常。当进程在所有数据写入之前退出时,就会出现这种情况。 stdin.

如果需要将数据发送到进程' stdin,需要使用创建流程 stdin=PIPE . 同样地,除了 None 在结果元组中,必须使用 stdout=PIPE 和/或 stderr=PIPE 参数。

注意,数据读取是在内存中进行缓冲的,因此如果数据大小很大或不受限制,则不要使用此方法。

send_signal(signal)

发送信号 信号 到子进程。

注解

在Windows上, SIGTERM 是一个别名 terminate() . CTRL_C_EVENTCTRL_BREAK_EVENT 可以发送到以 创建标志 参数,包括 CREATE_NEW_PROCESS_GROUP .

terminate()

停止子进程。

在POSIX系统上,此方法发送 signal.SIGTERM 到子进程。

在Windows上,win32 api函数 TerminateProcess() 调用以停止子进程。

kill()

停止子进程。

在POSIX系统上,此方法发送 SIGKILL 到子进程。

在Windows上,此方法是的别名 terminate() .

stdin

标准输入流 (StreamWriterNone 如果进程是用 stdin=None .

stdout

标准输出流 (StreamReaderNone 如果进程是用 stdout=None .

stderr

标准误差流 (StreamReaderNone 如果进程是用 stderr=None .

警告

使用 communicate() 方法而不是 process.stdin.write()await process.stdout.read()await process.stderr.read . 这避免了由于流暂停读或写以及阻塞子进程而导致的死锁。

pid

工艺标识号(PID)。

请注意,对于由 create_subprocess_shell() 函数,此属性是生成的shell的PID。

returncode

退出时返回进程的代码。

A None 值表示进程尚未终止。

负值 -N 指示子级已被信号终止 N (仅限POSIX)。

子进程和线程

默认情况下,标准异步事件循环支持从不同线程运行子进程。

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

在Unix上 儿童观察者 用于子进程完成等待,请参见 过程观察者 更多信息。

在 3.8 版更改: Unix已切换使用 ThreadedChildWatcher 用于从不同线程生成子进程而不受任何限制。

用生成子进程 不活动 当前子观察程序提升 RuntimeError .

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

实例

使用的示例 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}")

也见 same example 使用低级API编写。