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

返回一个Process实例。

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

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

返回一个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

asyncio 还具有以下低级 API 与子流程一起使用:loop.subprocess_exec()loop.subprocess_shell()loop.connect_read_pipe()loop.connect_write_pipe()以及Subprocess TransportsSubprocess Protocols

Constants

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

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

与子流程进行交互

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

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

此类为不是线程安全的

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

设置并返回returncode属性。

Note

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

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

返回一个 Tuples(stdout_data, stderr_data)

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

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

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

Note

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

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

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

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

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

Warning

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

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

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

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

子进程和线程

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

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

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

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

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

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

See also

异步中的并发和多线程部分。

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

首页