子进程 – 异步I / O(Python教程)(参考资料)
子进程
本节介绍高级异步/等待asyncio API创建和管理子进程.
这是一个asyncio如何运行shell命令并获得结果的示例:
import asyncioasync 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子进程函数都是异步的,并且异步开发了许多工具来处理这些函数,所以很容易并行执行和监视多个子进程。修改上面的例子同时运行几个命令确实是微不足道的:
async def main(): await asyncio.gather( run("ls /zzz"), run("sleep 1; echo "hello""))asyncio.run(main())
另见examples子部分.
创建子进程
- coroutine
asyncio.create_subprocess_exec(*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds) -
创建子进程.
limit argument为
StreamReader和Process.stdout设置Process.stderr包装器的缓冲区限制(如果subprocess.PIPE被传递到stdout和stderr参数).返回
Processinstance.参见
loop.subprocess_exec()对于其他参数
- coroutine
asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds) -
跑过 cmdshell命令.
limit参数为
StreamReader和Process.stdout设置Process.stderr包装器的缓冲区限制(如果subprocess.PIPE传递给stdout和stderr arguments).返回
Processinstance.
重要的
应用程序有责任确保适当地引用所有空格和特殊字符以避免shell注入漏洞。shlex.quote()函数可用于在用于构造shell命令的字符串中正确显示空格和特殊shell字符.
常数
asyncio.subprocess.PIPE-
可以传递到stdin, stdout或stderr参数
如果PIPE传递给stdin参数,
Process.stdin属性将指向StreamWriter实例如果PIPE传递到stdout或stderr参数,
Process.stdout和Process.stderr属性将指向toStreamReaderinstances.
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()函数创建的OS进程的对象.这个类的设计与
subprocess.Popen类有类似的API,但是有一些值得注意的差异:- 与Popen不同,Process实例没有等效的
poll()方法; -
communicate()和wait()方法没有timeout参数:使用wait_for()功能; -
Process.wait()methodis是异步的,而subprocess.Popen.wait()方法实现为阻塞忙循环; - 不支持universal_newlines参数.
这个类是不是线程安全的.
另见子进程和线程部分。
- coroutine
wait() -
等待子进程终止.
设置并返回
returncode属性。注意
使用
stdout=PIPE要么stderr=PIPE并且子进程生成了很多输出,它阻止等待OS管道缓冲区接受更多数据。使用管道时使用communicate()方法避免这种情况.
- coroutine
communicate(input=None ) -
与流程互动:
- 发送数据到stdin(如果input不是
None); - 从读取数据stdout和stderr,直到达到EOF;
- 等待进程终止.
可选input参数是将被发送到子进程的数据(
bytes对象)返回一个元组
(stdout_data, stderr_data).如果
BrokenPipeError或ConnectionResetError将input写入stdin,这个例外被忽略了。在将所有数据写入stdin.之前的processsexits时会发生这种情况。如果需要将数据发送到进程’stdin,需要用
stdin=PIPE创建进程。同样,要在结果元组中获取除None以外的任何内容,必须使用stdout=PIPE和/或stderr=PIPEarguments注意,读取的数据是缓冲在内存中的,所以如果数据量很大或不受限制,请不要使用这种方法.
- 发送数据到stdin(如果input不是
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到了childprocess.在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。这可以避免由于流暂停读取或写入而阻塞子进程导致的死锁.pid-
进程标识号(PID).
请注意,对于
create_subprocess_shell()函数创建的进程,此属性是生成的shell的PID .
returncode-
退出时返回进程的代码.
A
Nonevalue表示进程尚未终止.负值
-N表示孩子被信号终止N(仅限POSIX).
- 与Popen不同,Process实例没有等效的
子进程和线程
标准的asyncio事件循环支持从不同的线程运行子进程,但有一些限制:
- 一个事件循环必须在主线程中运行.
- 在执行其他线程的子进程之前,必须在主线程中实例化子监视器。调用主线程中的
get_child_watcher()函数来实例化子监视器.
注意替代事件循环实现可能不会分享上述限制;请参考他们的文档.
参见
asyncio中的并发和多线程 section.
示例
使用Process类控制子进程的示例和StreamReader类从标准输出读取
子进程由create_subprocess_exec()创建function:
import asyncioimport sysasync 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 lineif sys.platform == "win32": asyncio.set_event_loop_policy( asyncio.WindowsProactorEventLoopPolicy())date = asyncio.run(get_date())print(f"Current date: {date}")
参见同样的例子用低级API编写.
评论被关闭。