子進程集?
本節介紹了用于創建和管理子進程的高層級 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.stdout和Process.stderr設置StreamReader包裝器的緩沖區上限(如果將subprocess.PIPE傳給了 stdout 和 stderr 參數)。返回一個
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.stdout和Process.stderr設置StreamReader包裝器的緩沖區上限(如果將subprocess.PIPE傳給了 stdout 和 stderr 參數)。返回一個
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, 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()andcreate_subprocess_shell()函數創建的 OS 進程的對象。這個類被設計為具有與
subprocess.Popen類相似的 API,但兩者有一些重要的差異:不同于 Popen,Process 實例沒有與
poll()方法等價的方法;communicate()和wait()方法沒有 timeout 形參;要使用wait_for()函數;Process.wait()方法是異步的,而subprocess.Popen.wait()方法則被實現為阻塞型忙循環;universal_newlines 形參不被支持。
這個類不是線程安全的(not thread safe)。
請參閱 子進程和線程 部分。
-
coroutine
wait()? 等待子進程終結。
設置并返回
returncode屬性。注解
當使用
stdout=PIPE或stderr=PIPE并且子進程產生了足以阻塞 OS 管道緩沖區等待接收更多的數據的輸出時,此方法會發生死鎖。 當使用管道時請使用communicate()方法來避免這種情況。
-
coroutine
communicate(input=None)? 與進程交互:
發送數據到 stdin (如果 input 不為
None);從 stdout 和 stderr 讀取數據,直至到達 EOF;
等待進程終結。
可選的 input 參數為將被發送到子進程的數據 (
bytes對象)。返回一個元組
(stdout_data, stderr_data)。如果在將 input 寫入到 stdin 時引發了
BrokenPipeError或ConnectionResetError異常,異常會被忽略。 此條件會在進程先于所有數據被寫入到 stdin 之前退出時發生。如果想要將數據發送到進程的 stdin,則創建進程時必須使用
stdin=PIPE。 類似地,要在結果元組中獲得任何不為None的值,則創建進程時必須使用stdout=PIPE和/或stderr=PIPE參數。注意,數據讀取在內存中是帶緩沖的,因此如果數據量過大或不受則不要使用此方法。
-
send_signal(signal)? 將信號 signal 發送給子進程。
注解
在 Windows 上,
SIGTERM是terminate()的別名。CTRL_C_EVENT和CTRL_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.
參見
asyncio 中的并發和多線程 章節。
例子?
一個使用 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 編寫的 相同示例。
