子程序¶
原始碼: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
本節描述了高階的 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())
另請參閱 示例 小節。
建立子程序¶
- async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
建立一個子程序。
limit 引數設定
StreamReader
包裝器在stdout
和stderr
處的緩衝區限制(如果subprocess.PIPE
傳遞給 stdout 和 stderr 引數)。返回
Process
例項。有關其他引數,請參閱
loop.subprocess_exec()
的文件。版本 3.10 中已更改: 移除了 loop 引數。
- async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
執行 cmd shell 命令。
limit 引數設定
StreamReader
包裝器在stdout
和stderr
處的緩衝區限制(如果subprocess.PIPE
傳遞給 stdout 和 stderr 引數)。返回
Process
例項。有關其他引數,請參閱
loop.subprocess_shell()
的文件。重要
應用程式有責任確保所有空格和特殊字元都經過適當引用,以避免 shell 注入 漏洞。
shlex.quote()
函式可用於正確轉義用於構造 shell 命令的字串中的空格和特殊 shell 字元。版本 3.10 中已更改: 移除了 loop 引數。
備註
如果使用 ProactorEventLoop
,Windows 上也支援子程序。有關詳細資訊,請參閱 Windows 上的子程序支援。
參見
asyncio 還具有以下用於處理子程序的 低階 API:loop.subprocess_exec()
、loop.subprocess_shell()
、loop.connect_read_pipe()
、loop.connect_write_pipe()
,以及 子程序傳輸 和 子程序協議。
常量¶
- asyncio.subprocess.PIPE¶
可傳遞給 stdin、stdout 或 stderr 引數。
如果 PIPE 傳遞給 stdin 引數,
Process.stdin
屬性將指向StreamWriter
例項。如果 PIPE 傳遞給 stdout 或 stderr 引數,
Process.stdout
和Process.stderr
屬性將指向StreamReader
例項。
- asyncio.subprocess.STDOUT¶
特殊值,可用作 stderr 引數,表示標準錯誤應重定向到標準輸出。
- asyncio.subprocess.DEVNULL¶
特殊值,可用作程序建立函式中的 stdin、stdout 或 stderr 引數。它表示特殊檔案
os.devnull
將用於相應的子程序流。
與子程序互動¶
create_subprocess_exec()
和 create_subprocess_shell()
函式都返回 Process 類的例項。Process 是一個高階包裝器,允許與子程序通訊並監視它們的完成。
- class asyncio.subprocess.Process¶
一個物件,它包裝由
create_subprocess_exec()
和create_subprocess_shell()
函式建立的作業系統程序。此類的設計旨在提供與
subprocess.Popen
類相似的 API,但存在一些顯著差異與 Popen 不同,Process 例項沒有等效於
poll()
方法;communicate()
和wait()
方法沒有 timeout 引數:請使用wait_for()
函式;Process.wait()
方法是非同步的,而subprocess.Popen.wait()
方法是作為阻塞忙迴圈實現的;不支援 universal_newlines 引數。
此類 不是執行緒安全的。
另請參閱 子程序和執行緒 部分。
- async wait()¶
等待子程序終止。
設定並返回
returncode
屬性。備註
當使用
stdout=PIPE
或stderr=PIPE
且子程序生成過多輸出以至於在等待作業系統管道緩衝區接受更多資料時阻塞時,此方法可能會死鎖。使用管道時,請使用communicate()
方法以避免此情況。
- async communicate(input=None)¶
與程序互動
將資料傳送到 stdin(如果 input 不為
None
);關閉 stdin;
從 stdout 和 stderr 讀取資料,直到達到 EOF;
等待程序終止。
可選的 input 引數是將傳送到子程序的資料(
bytes
物件)。返回元組
(stdout_data, stderr_data)
。如果在將 input 寫入 stdin 時引發
BrokenPipeError
或ConnectionResetError
異常,則該異常將被忽略。當程序在所有資料寫入 stdin 之前退出時,會發生這種情況。如果希望向程序的 stdin 傳送資料,則需要使用
stdin=PIPE
建立程序。同樣,要在結果元組中獲取除None
之外的任何內容,必須使用stdout=PIPE
和/或stderr=PIPE
引數建立程序。請注意,讀取的資料在記憶體中緩衝,因此如果資料大小較大或不受限制,請勿使用此方法。
3.12 版本中的變化: 當
input=None
時,stdin 也會關閉。
- send_signal(signal)¶
向子程序傳送訊號 signal。
備註
在 Windows 上,
SIGTERM
是terminate()
的別名。CTRL_C_EVENT
和CTRL_BREAK_EVENT
可以傳送到透過包含CREATE_NEW_PROCESS_GROUP
的 creationflags 引數啟動的程序。
- terminate()¶
停止子程序。
在 POSIX 系統上,此方法向子程序傳送
SIGTERM
。在 Windows 上,呼叫 Win32 API 函式
TerminateProcess()
來停止子程序。
- kill()¶
終止子程序。
在 POSIX 系統上,此方法向子程序傳送
SIGKILL
。在 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¶
程序退出時的返回程式碼。
值為
None
表示程序尚未終止。負值
-N
表示子程序被訊號N
終止(僅限 POSIX)。
子程序和執行緒¶
預設情況下,標準的 asyncio 事件迴圈支援從不同執行緒執行子程序。
在 Windows 上,子程序僅由 ProactorEventLoop
提供(預設),SelectorEventLoop
不支援子程序。
請注意,替代事件迴圈實現可能存在自己的限制;請參閱其文件。
參見
示例¶
一個使用 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
date = asyncio.run(get_date())
print(f"Current date: {date}")
另請參閱使用低階 API 編寫的 相同示例。