On this page
Subprocesses
源代码: Lib/asyncio/subprocess.py,Lib/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.stdout
和Process.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.stdout
和Process.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
asyncio 还具有以下低级 API 与子流程一起使用:loop.subprocess_exec(),loop.subprocess_shell(),loop.connect_read_pipe(),loop.connect_write_pipe()以及Subprocess Transports和Subprocess Protocols。
Constants
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 *是高级包装程序,它允许与子流程进行通信并监视其完成情况。
- 类别
asyncio.subprocess.
Process
- 包裹由create_subprocess_exec()和create_subprocess_shell()函数创建的 OS 进程的对象。
此类设计为具有与subprocess.Popen类类似的 API,但有一些显着区别:
与 Popen 不同,Process 实例不具有poll()方法的等效项。
communicate()和wait()方法没有* timeout *参数:使用wait_for()函数;
Process.wait()方法是异步的,而subprocess.Popen.wait()方法被实现为阻塞繁忙循环;
不支持* universal_newlines *参数。
此类为不是线程安全的。
另请参见子进程和线程部分。
- 协程
wait
()- await 子进程终止。
设置并返回returncode属性。
Note
使用stdout=PIPE
或stderr=PIPE
时,此方法可能会死锁,并且子进程会生成大量输出,以至于阻塞 awaitOS 管道缓冲区接受更多数据的 await。使用管道时,请使用communicate()方法来避免这种情况。
协程
communicate
(Importing=无)- 与流程互动:
发送数据到* stdin (如果 input *不是
None
);从* stdout 和 stderr *读取数据,直到达到 EOF 为止;
await 进程终止。
可选的* input *参数是将发送到子进程的数据(bytes对象)。
返回一个 Tuples(stdout_data, stderr_data)
。
如果将* input 写入 stdin 时引发了BrokenPipeError或ConnectionResetError异常,则将忽略该异常。当在所有数据都写入 stdin *之前退出该进程时,会发生这种情况。
如果希望将数据发送到进程的* stdin *,则需要使用stdin=PIPE
创建该进程。同样,要在结果 Tuples 中获取除None
以外的任何内容,必须使用stdout=PIPE
和/或stderr=PIPE
参数创建该过程。
请注意,读取的数据缓存在内存中,因此,如果数据大小很大或没有限制,请不要使用此方法。
send_signal
(signal)- 将 signal* signal *发送到子进程。
Note
在 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
- 标准 Importing 流(StreamWriter)或
None
(如果进程是使用stdin=None
创建的)。
- 标准 Importing 流(StreamWriter)或
stdout
- 标准输出流(StreamReader)或
None
(如果进程是使用stdout=None
创建的)。
- 标准输出流(StreamReader)或
stderr
- 标准错误流(StreamReader)或
None
(如果进程是使用stderr=None
创建的)。
- 标准错误流(StreamReader)或
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。
注意,替代事件循环实现可能有其自身的局限性。请参阅其文档。
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。