子進(jìn)程集?

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


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

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

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

asyncio.run(main())

另請參閱 Examples 小節。

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

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

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

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

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

有關(guān)其他形參的說(shuō)明請查閱 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 參數為 Process.stdoutProcess.stderr 設置 StreamReader 包裝器的緩沖區上限(如果將 subprocess.PIPE 傳給了 stdoutstderr 參數)。

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

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

重要

應用程序要負責確保正確地轉義所有空白字符和特殊字符以防止 shell 注入 漏洞。 shlex.quote() 函數可以被用來(lái)正確地轉義字符串中可以被用來(lái)構造 shell 命令的空白字符和特殊 shell 字符。

在 3.10 版更改: Removed the loop parameter.

備注

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

參見(jià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 參數,則 Process.stdin 屬性將會(huì )指向一個(gè) StreamWriter 實(shí)例。

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

asyncio.subprocess.STDOUT?

可以用作 stderr 參數的特殊值,表示標準錯誤應當被重定向到標準輸出。

asyncio.subprocess.DEVNULL?

可以用作 stdin, stdoutstderr 參數來(lái)處理創(chuàng )建函數的特殊值。 它表示將為相應的子進(jìn)程流使用特殊文件 os.devnull。

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

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

class asyncio.subprocess.Process?

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

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

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

  • communicate()wait() 方法沒(méi)有 timeout 形參;要使用 wait_for() 函數;

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

  • universal_newlines 形參不被支持。

這個(gè)類(lèi)不是線(xiàn)程安全的(not thread safe)。

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

coroutine wait()?

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

設置并返回 returncode 屬性。

備注

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

coroutine communicate(input=None)?

與進(jìn)程交互:

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

  2. stdoutstderr 讀取數據,直至到達 EOF;

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

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

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

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

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

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

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 系統中此方法會(huì )發(fā)送 signal.SIGTERM 給子進(jìn)程。

在 Windows 上會(huì )調用 Win32 API 函數 TerminateProcess() 以停止子進(jìn)程。

kill()?

殺掉子進(jìn)程。

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

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

stdin?

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

stdout?

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

stderr?

標準錯誤流 (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)程標識號(PID)。

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

returncode?

當進(jìn)程退出時(shí)返回其代號。

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

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

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

標準 asyncio 事件循環(huán)默認支持從不同線(xiàn)程中運行子進(jìn)程。

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

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

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

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

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

例子?

一個(gè)使用 Process 類(lèi)來(lái)控制子進(jìn)程并用 StreamReader 類(lèi)來(lái)從其標準輸出讀取信息的示例。

這個(gè)子進(jìn)程是由 create_subprocess_exec() 函數創(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 編寫(xiě)的 相同示例。