进程

本节介绍高级异步/等待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为StreamReaderProcess.stdout设置Process.stderr包装器的缓冲区限制(如果subprocess.PIPE被传递到stdoutstderr参数).

返回Processinstance.

参见loop.subprocess_exec()对于其他参数​​

coroutine asyncio.create_subprocess_shellcmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds

跑过 cmdshell命令.

limit参数为StreamReaderProcess.stdout设置Process.stderr包装器的缓冲区限制(如果subprocess.PIPE传递给stdoutstderr arguments).

返回Process instance.

参见loop.subprocess_shell()其他参数.

重要的

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

注意

上默认的asyncio事件循环实现视窗不支持子流程。如果ProactorEventLoop用的。见Windows上的子进程支持详情.

参见

asyncio还有以下low-level API来处理子进程:loop.subprocess_exec(), loop.subprocess_shell(),loop.connect_read_pipe(), loop.connect_write_pipe(),以及 Subprocess Transports 子进程协议.

常数

asyncio.subprocess.PIPE

可以传递到stdin, stdoutstderr参数

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

如果PIPE传递到stdoutstderr参数,Process.stdoutProcess.stderr属性将指向to StreamReader instances.

asyncio.subprocess.STDOUT

可用作stderr参数的特殊值,表示标准错误应重定向到标准输出.

asyncio.subprocess.DEVNULL

特殊值可以用作stdin, stdoutstderr参数来处理创建函数。它表示特殊文件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 )

与流程互动:

  1. 发送数据到stdin(如果input不是 None);
  2. 从读取数据stdoutstderr,直到达到EOF;
  3. 等待进程终止.

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

返回一个元组(stdout_data, stderr_data).

如果BrokenPipeErrorConnectionResetErrorinput写入stdin,这个例外被忽略了。在将所有数据写入stdin.

之前的processsexits时会发生这种情况。如果需要将数据发送到进程’stdin,需要用stdin=PIPE创建进程。同样,要在结果元组中获取除None以外的任何内容,必须使用stdout=PIPE和/或stderr=PIPE arguments

注意,读取的数据是缓冲在内存中的,所以如果数据量很大或不受限制,请不要使用这种方法.

send_signal (signal)

发送信号signal对孩子的过程

注意

在Windows上,SIGTERMterminate().CTRL_C_EVENTCTRL_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).

子进程和线程

标准的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编写.

评论被关闭。