Subprocesses

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


本部分描述了用于创建和 Management 子流程的高级 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'))

will print:

['ls /zzz' exited with 1]
[stderr]
ls: /zzz: No such file or directory

因为所有 asyncio 子流程Function都是异步的,并且 asyncio 提供了许多工具来使用这些Function,所以很容易并行执行和监视多个子流程。修改上面的示例以同时运行多个命令确实很简单:

async def main():
    await asyncio.gather(
        run('ls /zzz'),
        run('sleep 1; echo "hello"'))

asyncio.run(main())

另请参见Examples小节。

Creating Subprocesses

  • 协程 asyncio. create_subprocess_exec(程序, *args stdin = None stdout = None stderr = None loop = None limit = None * kwds * )
    • 创建一个子流程。
  • limit 参数为Process.stdoutProcess.stderr设置StreamReader包装器的缓冲区限制(如果将subprocess.PIPE传递给 stdout stderr *参数)。

返回一个Process实例。

有关其他参数,请参见loop.subprocess_exec()的文档。

从 3.8 版开始不推荐使用,将在 3.10 版中删除:* loop *参数。

  • 协程 asyncio. create_subprocess_shell(* cmd stdin = None stdout = None stderr = None loop = None limit = None ** kwds *)
    • 运行* cmd * shell 命令。
  • limit 参数为Process.stdoutProcess.stderr设置StreamReader包装器的缓冲区限制(如果将subprocess.PIPE传递给 stdout stderr *参数)。

返回一个Process实例。

有关其他参数,请参见loop.subprocess_shell()的文档。

Important

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

从 3.8 版开始不推荐使用,将在 3.10 版中删除:* loop *参数。

Note

Windows **上的默认 asyncio 事件循环实现不支持子进程。如果使用ProactorEventLoop,则 subprocess 可用于 Windows。有关详情,请参见Windows 上的子流程支持

See also

Constants

  • asyncio.subprocess. PIPE
    • 可以传递给* stdin stdout stderr *参数。

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

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

  • asyncio.subprocess. STDOUT

    • 可以用作* stderr *参数的特殊值,指示应将标准错误重定向到标准输出。
  • asyncio.subprocess. DEVNULL

    • 可以用作进程创建函数的* stdin stdout stderr *参数的特殊值。它表示特殊文件os.devnull将用于相应的子流程流。

与子流程进行交互

create_subprocess_exec()create_subprocess_shell()函数都返回* Process *类的实例。 * Process *是高级包装程序,它允许与子流程进行通信并监视其完成情况。

此类设计为具有与subprocess.Popen类类似的 API,但有一些显着区别:

此类为不是线程安全的

另请参见子进程和线程部分。

  • 协程 wait()
    • await 子进程终止。

设置并返回returncode属性。

Note

使用stdout=PIPEstderr=PIPE时,此方法可能会死锁,并且子进程会生成大量输出,以至于阻塞 awaitOS 管道缓冲区接受更多数据的 await。使用管道时,请使用communicate()方法来避免这种情况。

  • 协程 communicate(Importing=无)

    • 与流程互动:
  • 发送数据到* stdin (如果 input *不是None);

  • 从* stdout stderr *读取数据,直到达到 EOF 为止;

  • await 进程终止。

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

返回一个 Tuples(stdout_data, stderr_data)

如果将* input 写入 stdin 时引发了BrokenPipeErrorConnectionResetError异常,则将忽略该异常。当在所有数据都写入 stdin *之前退出该进程时,会发生这种情况。

如果希望将数据发送到进程的* stdin *,则需要使用stdin=PIPE创建该进程。同样,要在结果 Tuples 中获取除None以外的任何内容,必须使用stdout=PIPE和/或stderr=PIPE参数创建该过程。

请注意,读取的数据缓存在内存中,因此,如果数据大小很大或没有限制,请不要使用此方法。

  • send_signal(signal)
    • 将 signal* signal *发送到子进程。

Note

在 Windows 上,SIGTERMterminate()的别名。可以将CTRL_C_EVENTCTRL_BREAK_EVENT发送到以* creationflags *参数(包括CREATE_NEW_PROCESS_GROUP)开始的进程。

  • terminate ( )
    • 停止子进程。

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

在 Windows 上,将调用 Win32 API 函数TerminateProcess()来停止子进程。

  • kill ( )
    • 杀死孩子

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

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

  • stdin

    • 标准 Importing 流(StreamWriter)或None(如果进程是使用stdin=None创建的)。
  • stdout

    • 标准输出流(StreamReader)或None(如果进程是使用stdout=None创建的)。
  • stderr

    • 标准错误流(StreamReader)或None(如果进程是使用stderr=None创建的)。

Warning

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

  • pid
    • 进程标识号(PID)。

请注意,对于由create_subprocess_shell()函数创建的进程,此属性是生成的 Shell 的 PID。

  • returncode
    • 退出时返回进程的代码。

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

负值-N表示该子级已被 signalN终止(仅 POSIX)。

子进程和线程

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

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

在 UNIX 上,* child watchers *用于子进程完成 await,有关更多信息,请参见Process Watchers

在版本 3.8 中进行了更改:UNIX 切换为使用ThreadedChildWatcher从不同线程生成子进程,而没有任何限制。

用当前非活动的 child 观察者生成子流程会引发RuntimeError

注意,替代事件循环实现可能有其自身的局限性。请参阅其文档。

Examples

一个使用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 编写的same example