子进程 – 异步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参数).返回
Process
instance.参见
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).返回
Process
instance.
重要的
应用程序有责任确保适当地引用所有空格和特殊字符以避免shell注入漏洞。shlex.quote()
函数可用于在用于构造shell命令的字符串中正确显示空格和特殊shell字符.
常数
asyncio.subprocess.
PIPE
-
可以传递到stdin, stdout或stderr参数
如果PIPE传递给stdin参数,
Process.stdin
属性将指向StreamWriter
实例如果PIPE传递到stdout或stderr参数,
Process.stdout
和Process.stderr
属性将指向toStreamReader
instances.
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=PIPE
arguments注意,读取的数据是缓冲在内存中的,所以如果数据量很大或不受限制,请不要使用这种方法.
- 发送数据到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
None
value表示进程尚未终止.负值
-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编写.
评论被关闭。