策略

事件迴圈策略是一個全域性物件,用於獲取和設定當前事件迴圈,以及建立新的事件迴圈。預設策略可以透過替換內建的替代方案來使用不同的事件迴圈實現,或者用可以覆蓋這些行為的自定義策略來替換。

策略物件獲取和設定每個上下文的單獨事件迴圈。預設情況下,這是每個執行緒的,但自定義策略可能會以不同的方式定義上下文

自定義事件迴圈策略可以控制get_event_loop()set_event_loop()new_event_loop() 的行為。

策略物件應實現AbstractEventLoopPolicy抽象基類中定義的 API。

獲取和設定策略

可以使用以下函式來獲取和設定當前程序的策略

asyncio.get_event_loop_policy()

返回當前程序範圍的策略。

asyncio.set_event_loop_policy(policy)

將當前程序範圍的策略設定為 policy

如果將 policy 設定為 None,則恢復預設策略。

策略物件

抽象事件迴圈策略基類定義如下

class asyncio.AbstractEventLoopPolicy

asyncio 策略的抽象基類。

get_event_loop()

獲取當前上下文的事件迴圈。

返回實現AbstractEventLoop 介面的事件迴圈物件。

此方法永遠不應返回 None

在 3.6 版本中更改。

set_event_loop(loop)

將當前上下文的事件迴圈設定為 loop

new_event_loop()

建立並返回新的事件迴圈物件。

此方法永遠不應返回 None

get_child_watcher()

獲取子程序監視器物件。

返回實現 AbstractChildWatcher 介面的監視器物件。

此函式特定於 Unix。

在 3.12 版本中棄用。

set_child_watcher(watcher)

將當前子程序監視器設定為 watcher

此函式特定於 Unix。

在 3.12 版本中棄用。

asyncio 附帶以下內建策略

class asyncio.DefaultEventLoopPolicy

預設的 asyncio 策略。在 Unix 上使用 SelectorEventLoop,在 Windows 上使用 ProactorEventLoop

無需手動安裝預設策略。asyncio 配置為自動使用預設策略。

在 3.8 版本中更改:在 Windows 上,現在預設使用 ProactorEventLoop

在 3.12 版本中棄用:如果沒有設定當前事件迴圈並且它決定建立一個,則預設 asyncio 策略的 get_event_loop() 方法現在會發出 DeprecationWarning。在未來的某個 Python 版本中,這將變成錯誤。

class asyncio.WindowsSelectorEventLoopPolicy

使用 SelectorEventLoop 事件迴圈實現的替代事件迴圈策略。

可用性:Windows。

class asyncio.WindowsProactorEventLoopPolicy

使用 ProactorEventLoop 事件迴圈實現的替代事件迴圈策略。

可用性:Windows。

程序監視器

程序監視器允許自定義事件迴圈如何在 Unix 上監視子程序。具體來說,事件迴圈需要知道子程序何時退出。

在 asyncio 中,使用 create_subprocess_exec()loop.subprocess_exec() 函式建立子程序。

asyncio 定義了 AbstractChildWatcher 抽象基類,子監視器應實現該基類,並且有四種不同的實現:ThreadedChildWatcher(配置為預設使用)、MultiLoopChildWatcherSafeChildWatcherFastChildWatcher

另請參閱 子程序和執行緒 部分。

以下兩個函式可用於自定義 asyncio 事件迴圈使用的子程序監視器實現

asyncio.get_child_watcher()

返回當前策略的當前子監視器。

在 3.12 版本中棄用。

asyncio.set_child_watcher(watcher)

將當前策略的當前子監視器設定為 watcherwatcher 必須實現 AbstractChildWatcher 基類中定義的方法。

在 3.12 版本中棄用。

注意

第三方事件迴圈實現可能不支援自定義子監視器。對於此類事件迴圈,使用 set_child_watcher() 可能會被禁止或不起作用。

class asyncio.AbstractChildWatcher
add_child_handler(pid, callback, *args)

註冊一個新的子程序處理程式。

安排在 PID 等於 pid 的程序終止時呼叫 callback(pid, returncode, *args)。 為同一程序指定另一個回撥將替換先前的處理程式。

callback 可呼叫物件必須是執行緒安全的。

remove_child_handler(pid)

移除 PID 等於 pid 的程序的處理程式。

如果成功移除處理程式,則該函式返回 True,如果沒有任何內容可移除,則返回 False

attach_loop(loop)

將監視器附加到事件迴圈。

如果監視器之前已附加到事件迴圈,則在附加到新迴圈之前,會先將其分離。

注意:loop 可以為 None

is_active()

如果監視器可以使用,則返回 True

使用 非活躍 當前子程序監視器生成子程序會引發 RuntimeError

在 3.8 版本中新增。

close()

關閉監視器。

必須呼叫此方法以確保清理底層資源。

在 3.12 版本中棄用。

class asyncio.ThreadedChildWatcher

此實現為每個子程序生成啟動一個新的等待執行緒。

即使 asyncio 事件迴圈在非主作業系統執行緒中執行,它也能可靠地工作。

處理大量子程序時沒有明顯的開銷(每次子程序終止時為 O(1)),但是每個程序啟動一個執行緒需要額外的記憶體。

此監視器預設使用。

在 3.8 版本中新增。

class asyncio.MultiLoopChildWatcher

此實現會在例項化時註冊一個 SIGCHLD 訊號處理程式。 這可能會破壞為 SIGCHLD 訊號安裝自定義處理程式的第三方程式碼。

監視器透過在 SIGCHLD 訊號上顯式輪詢每個程序來避免干擾其他生成程序的程式碼。

一旦安裝了監視器,從不同執行緒執行子程序就沒有限制。

該解決方案是安全的,但是在處理大量程序時會產生明顯的開銷(每次接收到 SIGCHLD 時為 O(n))。

在 3.8 版本中新增。

在 3.12 版本中棄用。

class asyncio.SafeChildWatcher

此實現使用主執行緒中的活動事件迴圈來處理 SIGCHLD 訊號。如果主執行緒沒有執行的事件迴圈,則另一個執行緒無法生成子程序(會引發 RuntimeError)。

監視器透過在 SIGCHLD 訊號上顯式輪詢每個程序來避免干擾其他生成程序的程式碼。

此解決方案與 MultiLoopChildWatcher 一樣安全,並且具有相同的 O(n) 複雜度,但是需要在主執行緒中執行事件迴圈才能工作。

在 3.12 版本中棄用。

class asyncio.FastChildWatcher

此實現透過直接呼叫 os.waitpid(-1) 來回收每個終止的程序,可能會破壞其他生成程序並等待其終止的程式碼。

處理大量子程序時沒有明顯的開銷(每次子程序終止時為 O(1))。

此解決方案需要在主執行緒中執行事件迴圈才能工作,如 SafeChildWatcher

在 3.12 版本中棄用。

class asyncio.PidfdChildWatcher

此實現輪詢程序檔案描述符 (pidfds) 以等待子程序終止。 在某些方面,PidfdChildWatcher 是一個“金髮姑娘”子程序監視器實現。 它不需要訊號或執行緒,不會干擾事件迴圈之外啟動的任何程序,並且隨著事件迴圈啟動的子程序數量線性擴充套件。 主要缺點是 pidfds 是 Linux 特有的,並且僅在最新的 (5.3+) 核心上工作。

在 3.9 版本中新增。

自定義策略

要實現新的事件迴圈策略,建議對 DefaultEventLoopPolicy 進行子類化,並覆蓋需要自定義行為的方法,例如:

class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):

    def get_event_loop(self):
        """Get the event loop.

        This may be None or an instance of EventLoop.
        """
        loop = super().get_event_loop()
        # Do something with loop ...
        return loop

asyncio.set_event_loop_policy(MyEventLoopPolicy())