18.5.6. 子进程 — Python 文档

来自菜鸟教程
Python/docs/3.6/library/asyncio-subprocess
跳转至:导航、​搜索

18.5.6. 子进程

源代码: :source:`Lib/asyncio/subprocess.py`

18.5.6.1. Windows 事件循环

在 Windows 上,默认的事件循环是 SelectorEventLoop,它不支持子进程。 ProactorEventLoop 应该被使用。 在 Windows 上使用它的示例:

import asyncio, sys

if sys.platform == 'win32':
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)

也可以看看

可用的事件循环平台支持


18.5.6.2. 创建子流程:使用 Process 的高级 API

使用 AbstractEventLoop.connect_read_pipe()AbstractEventLoop.connect_write_pipe() 方法连接管道。


18.5.6.3. 创建子流程:使用 subprocess.Popen 的低级 API

使用 subprocess 模块异步运行子进程。

也可以看看

AbstractEventLoop.connect_read_pipe()AbstractEventLoop.connect_write_pipe() 方法。


18.5.6.4. 常数

asyncio.subprocess.PIPE
可用作 create_subprocess_shell()create_subprocess_exec()stdinstdoutstderr 参数的特殊值,并指示应该打开到标准流的管道。
asyncio.subprocess.STDOUT
可用作 create_subprocess_shell()create_subprocess_exec()stderr 参数的特殊值,并指示标准错误应进入与标准输出相同的句柄。
asyncio.subprocess.DEVNULL
可用作 create_subprocess_shell()create_subprocess_exec()stdinstdoutstderr 参数的特殊值,并指示将使用特殊文件 os.devnull


18.5.6.5. 过程

class asyncio.subprocess.Process

create_subprocess_exec()create_subprocess_shell() 函数创建的子流程。

Process类的API被设计为接近于subprocess.Popen类的API,但是有一些区别:

  • 没有明确的 poll() 方法

  • communicate()wait() 方法不带 timeout 参数:使用 wait_for() 函数

  • 不支持 universal_newlines 参数(仅支持字节字符串)

  • Process 类的 wait() 方法是异步的,而 Popen 类的 wait() 方法是作为忙循环实现的。

此类是 不是线程安全的 。 另请参阅 子进程和线程 部分。

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 发送给子进程。 在 Windows 上 kill()terminate() 的别名。

stdin

标准输入流 (StreamWriter),如果进程是用 stdin=None 创建的,则为 None

stdout

标准输出流 (StreamReader),如果进程是用 stdout=None 创建的,则为 None

stderr

标准错误流 (StreamReader),None 如果进程是用 stderr=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 类不是线程安全的。

也可以看看

asyncio 部分中的 并发和多线程。


18.5.6.7. 子流程示例

18.5.6.7.1。 使用传输和协议的子进程

用于获取子进程输出并等待子进程退出的子进程协议示例。 子进程由 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。 使用流的子进程

使用 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()