子進程集?
本節(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, loop=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()的文檔。
-
coroutine
asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=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)用程序要負(fù)責(zé)確保正確地轉(zhuǎn)義所有空白字符和特殊字符以防止 shell 注入 漏洞。 shlex.quote() 函數(shù)可以被用來正確地轉(zhuǎn)義字符串中可以被用來構(gòu)造 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() 以及 子進程傳輸 和 子進程協(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ù)的特殊值,表示標(biāo)準(zhǔn)錯誤應(yīng)當(dāng)被重定向到標(biāo)準(zhǔn)輸出。
-
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屬性。注解
當(dāng)使用
stdout=PIPE或stderr=PIPE并且子進程產(chǎn)生了足以阻塞 OS 管道緩沖區(qū)等待接收更多的數(shù)據(jù)的輸出時,此方法會發(fā)生死鎖。 當(dāng)使用管道時請使用communicate()方法來避免這種情況。
-
coroutine
communicate(input=None)? 與進程交互:
發(fā)送數(shù)據(jù)到 stdin (如果 input 不為
None);從 stdout 和 stderr 讀取數(shù)據(jù),直至到達(dá) 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)建時附帶 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? 標(biāo)準(zhǔn)輸入流 (
StreamWriter) 或者如果進程創(chuàng)建時設(shè)置了``stdin=None`` 則為None。
-
stdout? 標(biāo)準(zhǔn)輸出流 (
StreamReader) 或者如果進程創(chuàng)建時設(shè)置了stdout=None則為None。
-
stderr? 標(biāo)準(zhǔn)錯誤流 (
StreamReader) 或者如果進程創(chuàng)建時設(shè)置了stderr=None則為None。
警告
使用
communicate()方法而非process.stdin.write(),await process.stdout.read()或await process.stderr.read。 這可以避免由于流暫停讀取或?qū)懭氩⒆枞舆M程而導(dǎo)致的死鎖。-
pid? 進程標(biāo)識號(PID)。
注意對于由Note that for processes created by the
create_subprocess_shell()函數(shù)所創(chuàng)建的進程,這個屬性將是所生成的 shell 的 PID。
-
returncode? 當(dāng)進程退出時返回其代號。
None值表示進程尚未終止。一個負(fù)值
-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 中的并發(fā)和多線程 章節(jié)。
例子?
一個使用 Process 類來控制子進程并用 StreamReader 類來從其標(biāo)準(zhǔn)輸出讀取信息的例子。
這個子進程是由 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
if sys.platform == "win32":
asyncio.set_event_loop_policy(
asyncio.WindowsProactorEventLoopPolicy())
date = asyncio.run(get_date())
print(f"Current date: {date}")
另請參閱使用低層級 API 編寫的 相同示例。
