子進(jìn)程集?

源代碼: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py


本節(jié)介紹了用于創(chuàng)建和管理子進(jìn)程的高層級 async/await asyncio API。

下面的例子演示了如何用 asyncio 運(yùn)行一個 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 子進(jìn)程函數(shù)都是異步的并且 asyncio 提供了許多工具用來配合這些函數(shù)使用,因此并行地執(zhí)行和監(jiān)視多個子進(jìn)程十分容易。 要修改上面的例子來同時運(yùn)行多個命令確實(shí)是非常簡單的:

async def main():
    await asyncio.gather(
        run('ls /zzz'),
        run('sleep 1; echo "hello"'))

asyncio.run(main())

另請參閱 Examples 小節(jié)。

創(chuàng)建子進(jìn)程?

coroutine asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)?

創(chuàng)建一個子進(jìn)程。

limit 參數(shù)為 Process.stdoutProcess.stderr 設(shè)置 StreamReader 包裝器的緩沖區(qū)上限(如果將 subprocess.PIPE 傳給了 stdoutstderr 參數(shù))。

返回一個 Process 實(shí)例。

有關(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)?

運(yùn)行 cmd shell 命令。

limit 參數(shù)為 Process.stdoutProcess.stderr 設(shè)置 StreamReader 包裝器的緩沖區(qū)上限(如果將 subprocess.PIPE 傳給了 stdoutstderr 參數(shù))。

返回一個 Process 實(shí)例。

有關(guān)其他形參的說明請查閱 loop.subprocess_shell() 的文檔。

重要

應(yīng)用程序要負(fù)責(zé)確保正確地轉(zhuǎn)義所有空白字符和特殊字符以防止 shell 注入 漏洞。 shlex.quote() 函數(shù)可以被用來正確地轉(zhuǎn)義字符串中可以被用來構(gòu)造 shell 命令的空白字符和特殊 shell 字符。

在 3.10 版更改: Removed the loop parameter.

備注

如果使用了 ProactorEventLoop 則子進(jìn)程將在 Windows 中可用。 詳情參見 Windows 上的子進(jìn)程支持。

參見

asyncio 還有下列 低層級 API 可配合子進(jìn)程使用: loop.subprocess_exec(), loop.subprocess_shell(), loop.connect_read_pipe(), loop.connect_write_pipe() 以及 子進(jìn)程傳輸子進(jìn)程協(xié)議

常量?

asyncio.subprocess.PIPE?

可以被傳遞給 stdin, stdoutstderr 形參。

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

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

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)的子進(jìn)程流使用特殊文件 os.devnull。

與子進(jìn)程交互?

create_subprocess_exec()create_subprocess_shell() 函數(shù)都返回 Process 類的實(shí)例。 Process 是一個高層級包裝器,它允許與子進(jìn)程通信并監(jiān)視其完成情況。

class asyncio.subprocess.Process?

一個用于包裝 create_subprocess_exec() and create_subprocess_shell() 函數(shù)創(chuàng)建的 OS 進(jìn)程的對象。

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

  • 不同于 Popen,Process 實(shí)例沒有與 poll() 方法等價的方法;

  • communicate()wait() 方法沒有 timeout 形參;要使用 wait_for() 函數(shù);

  • Process.wait() 方法是異步的,而 subprocess.Popen.wait() 方法則被實(shí)現(xiàn)為阻塞型忙循環(huán);

  • universal_newlines 形參不被支持。

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

請參閱 子進(jìn)程和線程 部分。

coroutine wait()?

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

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

備注

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

coroutine communicate(input=None)?

與進(jìn)程交互:

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

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

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

可選的 input 參數(shù)為將被發(fā)送到子進(jìn)程的數(shù)據(jù) (bytes 對象)。

返回一個元組 (stdout_data, stderr_data)。

如果在將 input 寫入到 stdin 時引發(fā)了 BrokenPipeErrorConnectionResetError 異常,異常會被忽略。 此條件會在進(jìn)程先于所有數(shù)據(jù)被寫入到 stdin 之前退出時發(fā)生。

如果想要將數(shù)據(jù)發(fā)送到進(jìn)程的 stdin,則創(chuàng)建進(jìn)程時必須使用 stdin=PIPE。 類似地,要在結(jié)果元組中獲得任何不為 None 的值,則創(chuàng)建進(jìn)程時必須使用 stdout=PIPE 和/或 stderr=PIPE 參數(shù)。

注意,數(shù)據(jù)讀取在內(nèi)存中是帶緩沖的,因此如果數(shù)據(jù)量過大或不受則不要使用此方法。

send_signal(signal)?

將信號 signal 發(fā)送給子進(jìn)程。

備注

在 Windows 上,SIGTERMterminate() 的別名。 CTRL_C_EVENTCTRL_BREAK_EVENT 可被發(fā)送給創(chuàng)建時設(shè)置了 creationflags 形參且其中包括 CREATE_NEW_PROCESS_GROUP 的進(jìn)程。

terminate()?

停止子進(jìn)程。

在 POSIX 系統(tǒng)中此方法會發(fā)送 signal.SIGTERM 給子進(jìn)程。

在 Windows 上會調(diào)用 Win32 API 函數(shù) TerminateProcess() 以停止子進(jìn)程。

kill()?

殺掉子進(jìn)程。

在 POSIX 系統(tǒng)中此方法會發(fā)送 SIGKILL 給子進(jìn)程。

在 Windows 上此方法是 terminate() 的別名。

stdin?

標(biāo)準(zhǔn)輸入流 (StreamWriter) 或者如果進(jìn)程創(chuàng)建時設(shè)置了 stdin=None 則為 None。

stdout?

標(biāo)準(zhǔn)輸出流 (StreamReader) 或者如果進(jìn)程創(chuàng)建時設(shè)置了 stdout=None 則為 None

stderr?

標(biāo)準(zhǔn)錯誤流 (StreamReader) 或者如果進(jìn)程創(chuàng)建時設(shè)置了 stderr=None 則為 None。

警告

Use the communicate() method rather than process.stdin.write(), await process.stdout.read() or await process.stderr.read(). This avoids deadlocks due to streams pausing reading or writing and blocking the child process.

pid?

進(jìn)程標(biāo)識號(PID)。

注意對于由Note that for processes created by the create_subprocess_shell() 函數(shù)所創(chuàng)建的進(jìn)程,這個屬性將是所生成的 shell 的 PID。

returncode?

當(dāng)進(jìn)程退出時返回其代號。

None 值表示進(jìn)程尚未終止。

一個負(fù)值 -N 表示子進(jìn)程被信號 N 中斷 (僅 POSIX).

子進(jìn)程和線程?

標(biāo)準(zhǔn) asyncio 事件循環(huán)默認(rèn)支持從不同線程中運(yùn)行子進(jìn)程。

在 Windows 上子進(jìn)程(默認(rèn))只由 ProactorEventLoop 提供,SelectorEventLoop 沒有子進(jìn)程支持。

在 UNIX 上會使用 child watchers 來讓子進(jìn)程結(jié)束等待,詳情請參閱 進(jìn)程監(jiān)視器。

在 3.8 版更改: UNIX 對于從不同線程中無限制地生成子進(jìn)程會切換為使用 ThreadedChildWatcher。

使用 不活動的 當(dāng)前子監(jiān)視器生成子進(jìn)程將引發(fā) RuntimeError

請注意其他的事件循環(huán)實(shí)現(xiàn)可能有其本身的限制;請查看它們各自的文檔。

參見

asyncio 中的并發(fā)和多線程 章節(jié)。

例子?

一個使用 Process 類來控制子進(jìn)程并用 StreamReader 類來從其標(biāo)準(zhǔn)輸出讀取信息的示例。

這個子進(jì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

date = asyncio.run(get_date())
print(f"Current date: {date}")

另請參閱使用低層級 API 編寫的 相同示例。