子進程集?

本節(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.stdoutProcess.stderr 設(shè)置 StreamReader 包裝器的緩沖區(qū)上限(如果將 subprocess.PIPE 傳給了 stdoutstderr 參數(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.stdoutProcess.stderr 設(shè)置 StreamReader 包裝器的緩沖區(qū)上限(如果將 subprocess.PIPE 傳給了 stdoutstderr 參數(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, stdoutstderr 形參。

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

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

asyncio.subprocess.STDOUT?

可以用作 stderr 參數(shù)的特殊值,表示標(biāo)準(zhǔn)錯誤應(yīng)當(dāng)被重定向到標(biāo)準(zhǔn)輸出。

asyncio.subprocess.DEVNULL?

可以用作 stdin, stdoutstderr 參數(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() and create_subprocess_shell() 函數(shù)創(chuàng)建的 OS 進程的對象。

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

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

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

coroutine wait()?

等待子進程終結(jié)。

設(shè)置并返回 returncode 屬性。

注解

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

coroutine communicate(input=None)?

與進程交互:

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

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

  3. 等待進程終結(jié)。

可選的 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。 類似地,要在結(jié)果元組中獲得任何不為 None 的值,則創(chuàng)建進程時必須使用 stdout=PIPE 和/或 stderr=PIPE 參數(shù)。

注意,數(shù)據(jù)讀取在內(nèi)存中是帶緩沖的,因此如果數(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 上會調(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 編寫的 相同示例。