子進程集?
源代碼: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
本節(jié)介紹了用于創(chuàng)建和管理子進程的高層級 async/await asyncio API。
下面的例子演示了如何用 asyncio 運行一個 shell 命令并獲取其結(jié)果:
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.stdout
和Process.stderr
設(shè)置StreamReader
包裝器的緩沖區(qū)上限(如果將subprocess.PIPE
傳給了 stdout 和 stderr 參數(shù))。返回一個
Process
實例。有關(guān)其他形參的說明請查閱
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.stdout
和Process.stderr
設(shè)置StreamReader
包裝器的緩沖區(qū)上限(如果將subprocess.PIPE
傳給了 stdout 和 stderr 參數(shù))。返回一個
Process
實例。有關(guān)其他形參的說明請查閱
loop.subprocess_shell()
的文檔。重要
應(yīng)用程序要負責(zé)確保正確地轉(zhuǎn)義所有空白字符和特殊字符以防止 shell 注入 漏洞。
shlex.quote()
函數(shù)可以被用來正確地轉(zhuǎn)義字符串中可以被用來構(gòu)造 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, stdout 或 stderr 形參。
如果 PIPE 被傳遞給 stdin 參數(shù),則
Process.stdin
屬性將會指向一個StreamWriter
實例。如果 PIPE 被傳遞給 stdout 或 stderr 參數(shù),則
Process.stdout
和Process.stderr
屬性將會指向StreamReader
實例。
- asyncio.subprocess.STDOUT?
可以用作 stderr 參數(shù)的特殊值,表示標準錯誤應(yīng)當被重定向到標準輸出。
- asyncio.subprocess.DEVNULL?
可以用作 stdin, stdout 或 stderr 參數(shù)來處理創(chuàng)建函數(shù)的特殊值。 它表示將為相應(yīng)的子進程流使用特殊文件
os.devnull
。
與子進程交互?
create_subprocess_exec()
和 create_subprocess_shell()
函數(shù)都返回 Process 類的實例。 Process 是一個高層級包裝器,它允許與子進程通信并監(jiān)視其完成情況。
- class asyncio.subprocess.Process?
一個用于包裝
create_subprocess_exec()
andcreate_subprocess_shell()
函數(shù)創(chuàng)建的 OS 進程的對象。這個類被設(shè)計為具有與
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()?
等待子進程終結(jié)。
設(shè)置并返回
returncode
屬性。備注
當使用
stdout=PIPE
或stderr=PIPE
并且子進程產(chǎn)生了足以阻塞 OS 管道緩沖區(qū)等待接收更多的數(shù)據(jù)的輸出時,此方法會發(fā)生死鎖。 當使用管道時請使用communicate()
方法來避免這種情況。
- coroutine communicate(input=None)?
與進程交互:
發(fā)送數(shù)據(jù)到 stdin (如果 input 不為
None
);從 stdout 和 stderr 讀取數(shù)據(jù),直至到達 EOF;
等待進程終結(jié)。
可選的 input 參數(shù)為將被發(fā)送到子進程的數(shù)據(jù) (
bytes
對象)。返回一個元組
(stdout_data, stderr_data)
。如果在將 input 寫入到 stdin 時引發(fā)了
BrokenPipeError
或ConnectionResetError
異常,異常會被忽略。 此條件會在進程先于所有數(shù)據(jù)被寫入到 stdin 之前退出時發(fā)生。如果想要將數(shù)據(jù)發(fā)送到進程的 stdin,則創(chuàng)建進程時必須使用
stdin=PIPE
。 類似地,要在結(jié)果元組中獲得任何不為None
的值,則創(chuàng)建進程時必須使用stdout=PIPE
和/或stderr=PIPE
參數(shù)。注意,數(shù)據(jù)讀取在內(nèi)存中是帶緩沖的,因此如果數(shù)據(jù)量過大或不受則不要使用此方法。
- send_signal(signal)?
將信號 signal 發(fā)送給子進程。
備注
在 Windows 上,
SIGTERM
是terminate()
的別名。CTRL_C_EVENT
和CTRL_BREAK_EVENT
可被發(fā)送給創(chuàng)建時設(shè)置了 creationflags 形參且其中包括CREATE_NEW_PROCESS_GROUP
的進程。
- terminate()?
停止子進程。
在 POSIX 系統(tǒng)中此方法會發(fā)送
signal.SIGTERM
給子進程。在 Windows 上會調(diào)用 Win32 API 函數(shù)
TerminateProcess()
以停止子進程。
- kill()?
殺掉子進程。
在 POSIX 系統(tǒng)中此方法會發(fā)送
SIGKILL
給子進程。在 Windows 上此方法是
terminate()
的別名。
- stdin?
標準輸入流 (
StreamWriter
) 或者如果進程創(chuàng)建時設(shè)置了stdin=None
則為None
。
- stdout?
標準輸出流 (
StreamReader
) 或者如果進程創(chuàng)建時設(shè)置了stdout=None
則為None
。
- stderr?
標準錯誤流 (
StreamReader
) 或者如果進程創(chuàng)建時設(shè)置了stderr=None
則為None
。
警告
Use the
communicate()
method rather thanprocess.stdin.write()
,await process.stdout.read()
orawait 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é)束等待,詳情請參閱 進程監(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 編寫的 相同示例。