18.5.6. Subprocess¶
18.5.6.1. Windows event loop¶
在Windows上,默认事件循环为SelectorEventLoop
,不支持子流程。应使用ProactorEventLoop
。在Windows上使用它的示例:
import asyncio, sys
if sys.platform == 'win32':
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
18.5.6.2. Create a subprocess: high-level API using Process¶
- coroutine
asyncio.
create_subprocess_exec
(*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)¶ 创建子过程。
limit参数设置传递到
StreamReader
的缓冲区限制。有关其他参数,请参阅AbstractEventLoop.subprocess_exec()
。返回
Process
实例。此函数是coroutine。
- coroutine
asyncio.
create_subprocess_shell
(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)¶ 运行shell命令cmd。
limit参数设置传递到
StreamReader
的缓冲区限制。有关其他参数,请参阅AbstractEventLoop.subprocess_shell()
。返回
Process
实例。应用程序有责任确保适当地引用所有空格和元字符以避免shell注入漏洞。
shlex.quote()
函数可用于正确地转义将用于构建shell命令的字符串中的空格和shell元字符。此函数是coroutine。
使用AbstractEventLoop.connect_read_pipe()
和AbstractEventLoop.connect_write_pipe()
方法来连接管道。
18.5.6.3. Create a subprocess: low-level API using subprocess.Popen¶
使用subprocess
模块异步运行子进程。
- coroutine
AbstractEventLoop.
subprocess_exec
(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)¶ 从一个或多个字符串参数(编码到filesystem encoding的字符串或字节字符串)创建子过程,其中第一个字符串指定要执行的程序,其余字符串指定程序的参数。(因此,一起的字符串参数形成程序的
sys.argv
值,假设它是一个Python脚本。)这类似于使用shell = False调用的标准库subprocess.Popen
类,以及作为第一个参数传递的字符串列表;然而,Popen
采用单个参数,它是字符串列表,subprocess_exec()
接受多个字符串参数。protocol_factory必须实例化
asyncio.SubprocessProtocol
类的子类。其他参数:
- stdin:使用
connect_write_pipe()
或常量subprocess.PIPE
默认情况下,将创建和连接新的管道。 - stdout:使用
connect_read_pipe()
或常量subprocess.PIPE
默认情况下,将创建和连接新的管道。 - stderr:表示要使用
connect_read_pipe()
连接到子过程的标准错误流的管道的文件状对象,或者是subprocess.PIPE
(默认值)或subprocess.STDOUT
。默认情况下,将创建和连接新的管道。当指定subprocess.STDOUT
时,子进程的标准错误流将连接到与标准输出流相同的管道。 - 除了bufsize,universal_newlines和shell,所有其他关键字参数都传递到
subprocess.Popen
不应该指定。
返回一对
(transport, 协议)
,其中transport是BaseSubprocessTransport
此方法是coroutine。
请参阅
subprocess.Popen
类的构造函数。- stdin:使用
- coroutine
AbstractEventLoop.
subprocess_shell
(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)¶ 使用平台的“shell”语法从cmd创建子过程,该子过程是一个字符串或编码为filesystem encoding的字节字符串。这类似于使用
shell=True
调用的标准库subprocess.Popen
类。protocol_factory必须实例化
asyncio.SubprocessProtocol
类的子类。有关其余参数的更多详细信息,请参见
subprocess_exec()
。返回一对
(transport, 协议)
,其中transport是BaseSubprocessTransport
应用程序有责任确保适当地引用所有空格和元字符以避免shell注入漏洞。
shlex.quote()
函数可用于正确地转义将用于构建shell命令的字符串中的空格和shell元字符。此方法是coroutine。
18.5.6.4. Constants¶
-
asyncio.subprocess.
PIPE
¶ Special value that can be used as the stdin, stdout or stderr argument to
create_subprocess_shell()
andcreate_subprocess_exec()
and indicates that a pipe to the standard stream should be opened.
-
asyncio.subprocess.
STDOUT
¶ 可用作
create_subprocess_shell()
和create_subprocess_exec()
的stderr参数的特殊值,表示标准错误应该进入相同的句柄作为标准输出。
-
asyncio.subprocess.
DEVNULL
¶ Special value that can be used as the stdin, stdout or stderr argument to
create_subprocess_shell()
andcreate_subprocess_exec()
and indicates that the special fileos.devnull
will be used.
18.5.6.5. Process¶
- class
asyncio.subprocess.
Process
¶ 由
create_subprocess_exec()
或create_subprocess_shell()
函数创建的子过程。Process
类的API设计为接近subprocess.Popen
类的API,但有一些区别:- 没有显式的
poll()
方法 communicate()
和wait()
方法不采用超时参数:使用wait_for()
- 不支持universal_newlines参数(仅支持字节字符串)
Process
类的wait()
方法是异步的,而Popen
类的wait()
实现为忙回路。
此类为not thread safe。另请参见Subprocess and threads部分。
- coroutine
wait
()¶ 等待子进程终止。设置并返回
returncode
属性。此方法是coroutine。
注意
当使用
stdout=PIPE
或stderr=PIPE
时,这将会死锁,子进程会向管道生成足够的输出,从而阻止等待操作系统管道缓冲区接受更多数据。在使用管道时避免使用communicate()
方法。
- coroutine
communicate
(input=None)¶ 与进程交互:将数据发送到stdin。从stdout和stderr读取数据,直到达到文件结束。等待进程终止。可选的输入参数应为要发送到子进程的数据,或
None
,如果没有数据应发送到子进程。输入的类型必须为字节。communicate()
返回一个元组(stdout_data, stderr_data)
。如果在将输入写入stdin时引发
BrokenPipeError
或ConnectionResetError
异常,则会忽略异常。它发生在进程退出之前所有数据都写入stdin。请注意,如果要将数据发送到进程的stdin,则需要使用
stdin=PIPE
创建Process对象。类似地,为了在结果元组中获得除None
之外的任何东西,您还需要给予stdout=PIPE
和/或stderr=PIPE
。此方法是coroutine。
注意
读取的数据在内存中缓冲,因此如果数据大小较大或无限制,则不要使用此方法。
在版本3.4.2中更改:此方法现在忽略
BrokenPipeError
和ConnectionResetError
。
-
send_signal
(signal)¶ 将信号信号发送到子进程。
注意
在Windows上,
SIGTERM
是terminate()
的别名。CTRL_C_EVENT
和CTRL_BREAK_EVENT
可发送到以creationflags参数(包括CREATE_NEW_PROCESS_GROUP
)开始的进程。
-
terminate
()¶ 停止孩子。在Posix OS上,方法向子进程发送
signal.SIGTERM
。在Windows上,调用Win32 API函数TerminateProcess()
来停止子进程。
-
kill
()¶ 杀死孩子。在Posix OS上,函数向子进程发送
SIGKILL
。在Windows上kill()
是terminate()
的别名。
-
stdin
¶ 标准输入流(
StreamWriter
),None
如果使用stdin=None
创建过程。
-
stdout
¶ 标准输出流(
StreamReader
),None
(如果使用stdout=None
创建过程)。
-
stderr
¶ 如果使用
stderr=None
创建过程,则标准错误流(StreamReader
),None
。
警告
使用
communicate()
方法,而不是.stdin.write
,.stdout.read
或.stderr.read
以避免由于流暂停读取或写入和阻塞子进程而导致的死锁。-
pid
¶ 进程的标识符。
请注意,对于由
create_subprocess_shell()
函数创建的进程,此属性是生成的shell的进程标识符。
-
returncode
¶ 退出时的进程的返回代码。
None
值表示进程尚未终止。负值
-N
表示子节点由信号N
(仅限Unix)终止。
- 没有显式的
18.5.6.6. 子进程和线程¶
asyncio支持从不同的线程中运行子进程,但有一些限制:
- 事件循环必须在主线程中运行
- 子监视器必须在主线程中实例化,然后从其他线程执行子进程。调用主线程中的
get_child_watcher()
函数来实例化子监视器。
asyncio.subprocess.Process
类不是线程安全的。
18.5.6.7. 子过程示例¶
18.5.6.7.1. Subprocess using transport and protocol¶
子进程协议的示例,用于获取子进程的输出并等待子进程退出。子过程由AbstractEventLoop.subprocess_exec()
方法创建:
import asyncio
import sys
class DateProtocol(asyncio.SubprocessProtocol):
def __init__(self, exit_future):
self.exit_future = exit_future
self.output = bytearray()
def pipe_data_received(self, fd, data):
self.output.extend(data)
def process_exited(self):
self.exit_future.set_result(True)
@asyncio.coroutine
def get_date(loop):
code = 'import datetime; print(datetime.datetime.now())'
exit_future = asyncio.Future(loop=loop)
# Create the subprocess controlled by the protocol DateProtocol,
# redirect the standard output into a pipe
create = loop.subprocess_exec(lambda: DateProtocol(exit_future),
sys.executable, '-c', code,
stdin=None, stderr=None)
transport, protocol = yield from create
# Wait for the subprocess exit using the process_exited() method
# of the protocol
yield from exit_future
# Close the stdout pipe
transport.close()
# Read the output which was collected by the pipe_data_received()
# method of the protocol
data = bytes(protocol.output)
return data.decode('ascii').rstrip()
if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
date = loop.run_until_complete(get_date(loop))
print("Current date: %s" % date)
loop.close()
18.5.6.7.2. Subprocess using streams¶
使用Process
类控制子进程和StreamReader
类从标准输出读取的示例。子过程由create_subprocess_exec()
函数创建:
import asyncio.subprocess
import sys
@asyncio.coroutine
def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess, redirect the standard output into a pipe
create = asyncio.create_subprocess_exec(sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
proc = yield from create
# Read one line of output
data = yield from proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit
yield from proc.wait()
return line
if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
date = loop.run_until_complete(get_date())
print("Current date: %s" % date)
loop.close()