子進程集?

源代碼: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py


本節(jié)介紹了用于創(chuàng)建和管理子進程的高層級 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 子進程函數(shù)都是異步的并且 asyncio 提供了許多工具用來配合這些函數(shù)使用,因此并行地執(zhí)行和監(jiān)視多個子進程十分容易。 要修改上面的例子來同時運行多個命令確實是非常簡單的:

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

asyncio.run(main())

另請參閱 Examples 小節(jié)。

創(chuàng)建子進程?

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

創(chuàng)建一個子進程。

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

返回一個 Process 實例。

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

在 3.10 版更改: Removed the loop parameter.

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

運行 cmd shell 命令。

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

返回一個 Process 實例。

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

重要

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

在 3.10 版更改: Removed the loop parameter.

備注

如果使用了 ProactorEventLoop 則子進程將在 Windows 中可用。 詳情參見 Windows 上的子進程支持。

參見

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

常量?

asyncio.subprocess.PIPE?

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

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

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

asyncio.subprocess.STDOUT?

可以用作 stderr 參數(shù)的特殊值,表示標準錯誤應當被重定向到標準輸出。

asyncio.subprocess.DEVNULL?

可以用作 stdin, stdoutstderr 參數(shù)來處理創(chuàng)建函數(shù)的特殊值。 它表示將為相應的子進程流使用特殊文件 os.devnull。

與子進程交互?

create_subprocess_exec()create_subprocess_shell() 函數(shù)都返回 Process 類的實例。 Process 是一個高層級包裝器,它允許與子進程通信并監(jiān)視其完成情況。

class asyncio.subprocess.Process?

一個用于包裝 create_subprocess_exec() and create_subprocess_shell() 函數(shù)創(chuàng)建的 OS 進程的對象。

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

  • 不同于 Popen,Process 實例沒有與 poll() 方法等價的方法;

  • communicate()wait() 方法沒有 timeout 形參;要使用 wait_for() 函數(shù);

  • Process.wait() 方法是異步的,而 subprocess.Popen.wait() 方法則被實現(xiàn)為阻塞型忙循環(huán);

  • universal_newlines 形參不被支持。

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

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

coroutine wait()?

等待子進程終結。

設置并返回 returncode 屬性。

備注

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

coroutine communicate(input=None)?

與進程交互:

  1. 發(fā)送數(shù)據(jù)到 stdin (如果 input 不為 None);

  2. stdoutstderr 讀取數(shù)據(jù),直至到達 EOF;

  3. 等待進程終結。

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

返回一個元組 (stdout_data, stderr_data)

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

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

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

send_signal(signal)?

將信號 signal 發(fā)送給子進程。

備注

在 Windows 上,SIGTERMterminate() 的別名。 CTRL_C_EVENTCTRL_BREAK_EVENT 可被發(fā)送給創(chuàng)建時設置了 creationflags 形參且其中包括 CREATE_NEW_PROCESS_GROUP 的進程。

terminate()?

停止子進程。

在 POSIX 系統(tǒng)中此方法會發(fā)送 signal.SIGTERM 給子進程。

在 Windows 上會調用 Win32 API 函數(shù) TerminateProcess() 以停止子進程。

kill()?

殺掉子進程。

在 POSIX 系統(tǒng)中此方法會發(fā)送 SIGKILL 給子進程。

在 Windows 上此方法是 terminate() 的別名。

stdin?

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

stdout?

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

stderr?

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

警告

Use the communicate() method rather than process.stdin.write(), await process.stdout.read() or await process.stderr.read(). This avoids deadlocks due to streams pausing reading or writing and blocking the child process.

pid?

進程標識號(PID)。

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

returncode?

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

None 值表示進程尚未終止。

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

子進程和線程?

標準 asyncio 事件循環(huán)默認支持從不同線程中運行子進程。

在 Windows 上子進程(默認)只由 ProactorEventLoop 提供,SelectorEventLoop 沒有子進程支持。

在 UNIX 上會使用 child watchers 來讓子進程結束等待,詳情請參閱 進程監(jiān)視器。

在 3.8 版更改: UNIX 對于從不同線程中無限制地生成子進程會切換為使用 ThreadedChildWatcher

使用 不活動的 當前子監(jiān)視器生成子進程將引發(fā) RuntimeError。

請注意其他的事件循環(huán)實現(xiàn)可能有其本身的限制;請查看它們各自的文檔。

參見

asyncio 中的并發(fā)和多線程 章節(jié)。

例子?

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

這個子進程是由 create_subprocess_exec() 函數(shù)創(chuàng)建的:

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

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

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