子進程集?

本節介紹了用于創建和管理子進程的高層級 async/await asyncio API。

下面的例子演示了如何用 asyncio 運行一個 shell 命令并獲取其結果:

import asyncio

async 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 子進程函數都是異步的并且 asyncio 提供了許多工具用來配合這些函數使用,因此并行地執行和監視多個子進程十分容易。 要修改上面的例子來同時運行多個命令確實是非常簡單的:

async def main():
    await asyncio.gather(
        run('ls /zzz'),
        run('sleep 1; echo "hello"'))

asyncio.run(main())

另請參閱 Examples 小節。

創建子進程?

coroutine asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)?

創建一個子進程。

limit 參數為 Process.stdoutProcess.stderr 設置 StreamReader 包裝器的緩沖區上限(如果將 subprocess.PIPE 傳給了 stdoutstderr 參數)。

返回一個 Process 實例。

有關其他形參的說明請查閱 loop.subprocess_exec() 的文檔。

coroutine asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)?

運行 cmd shell 命令。

limit 參數為 Process.stdoutProcess.stderr 設置 StreamReader 包裝器的緩沖區上限(如果將 subprocess.PIPE 傳給了 stdoutstderr 參數)。

返回一個 Process 實例。

有關其他形參的說明請查閱 loop.subprocess_shell() 的文檔。

重要

應用程序要負責確保正確地轉義所有空白字符和特殊字符以防止 shell 注入 漏洞。 shlex.quote() 函數可以被用來正確地轉義字符串中可以被用來構造 shell 命令的空白字符和特殊 shell 字符。

注解

The default asyncio event loop implementation on Windows does not support subprocesses. Subprocesses are available for Windows if a ProactorEventLoop is used. See Subprocess Support on Windows for details.

參見

asyncio 還有下列 低層級 API 可配合子進程使用: loop.subprocess_exec(), loop.subprocess_shell(), loop.connect_read_pipe(), loop.connect_write_pipe() 以及 子進程傳輸子進程協議

常量?

asyncio.subprocess.PIPE?

可以被傳遞給 stdin, stdoutstderr 形參。

如果 PIPE 被傳遞給 stdin 參數,則 Process.stdin 屬性將會指向一個 StreamWriter 實例。

如果 PIPE 被傳遞給 stdoutstderr 參數,則 Process.stdoutProcess.stderr 屬性將會指向 StreamReader 實例。

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() and create_subprocess_shell() 函數創建的 OS 進程的對象。

這個類被設計為具有與 subprocess.Popen 類相似的 API,但兩者有一些重要的差異:

這個類不是線程安全的(not thread safe)。

請參閱 子進程和線程 部分。

coroutine wait()?

等待子進程終結。

設置并返回 returncode 屬性。

注解

當使用 stdout=PIPEstderr=PIPE 并且子進程產生了足以阻塞 OS 管道緩沖區等待接收更多的數據的輸出時,此方法會發生死鎖。 當使用管道時請使用 communicate() 方法來避免這種情況。

coroutine communicate(input=None)?

與進程交互:

  1. 發送數據到 stdin (如果 input 不為 None);

  2. stdoutstderr 讀取數據,直至到達 EOF;

  3. 等待進程終結。

可選的 input 參數為將被發送到子進程的數據 (bytes 對象)。

返回一個元組 (stdout_data, stderr_data)

如果在將 input 寫入到 stdin 時引發了 BrokenPipeErrorConnectionResetError 異常,異常會被忽略。 此條件會在進程先于所有數據被寫入到 stdin 之前退出時發生。

如果想要將數據發送到進程的 stdin,則創建進程時必須使用 stdin=PIPE。 類似地,要在結果元組中獲得任何不為 None 的值,則創建進程時必須使用 stdout=PIPE 和/或 stderr=PIPE 參數。

注意,數據讀取在內存中是帶緩沖的,因此如果數據量過大或不受則不要使用此方法。

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 上此方法是 terminate() 的別名。

stdin?

標準輸入流 (StreamWriter) 或者如果進程創建時設置了``stdin=None`` 則為 None

stdout?

標準輸出流 (StreamReader) 或者如果進程創建時設置了 stdout=None 則為 None

stderr?

標準錯誤流 (StreamReader) 或者如果進程創建時設置了 stderr=None 則為 None

警告

使用 communicate() 方法而非 process.stdin.write(), await process.stdout.read()await process.stderr.read。 這可以避免由于流暫停讀取或寫入并阻塞子進程而導致的死鎖。

pid?

進程標識號(PID)。

注意對于由Note that for processes created by the create_subprocess_shell() 函數所創建的進程,這個屬性將是所生成的 shell 的 PID。

returncode?

當進程退出時返回其代號。

None 值表示進程尚未終止。

一個負值 -N 表示子進程被信號 N 中斷 (僅 POSIX).

子進程和線程?

Standard asyncio event loop supports running subprocesses from different threads, but there are limitations:

  • An event loop must run in the main thread.

  • The child watcher must be instantiated in the main thread before executing subprocesses from other threads. Call the get_child_watcher() function in the main thread to instantiate the child watcher.

Note that alternative event loop implementations might not share the above limitations; please refer to their documentation.

例子?

一個使用 Process 類來控制子進程并用 StreamReader 類來從其標準輸出讀取信息的例子。

這個子進程是由 create_subprocess_exec() 函數創建的:

import asyncio
import sys

async 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 line

if sys.platform == "win32":
    asyncio.set_event_loop_policy(
        asyncio.WindowsProactorEventLoopPolicy())

date = asyncio.run(get_date())
print(f"Current date: {date}")

另請參閱使用低層級 API 編寫的 相同示例