策略?

事件循環(huán)策略是各個進程的全局對象 ,它控制事件循環(huán)的管理。每個事件循環(huán)都有一個默認策略,可以使用策略API更改和定制該策略。

策略定義了“上下文”的概念,每個上下文管理一個單獨的事件循環(huán)。默認策略將*context*定義為當前線程。

通過使用自定義事件循環(huán)策略,可以自定義 get_event_loop() 、 set_event_loop()new_event_loop() 函數(shù)的行為。

策略對象應該實現(xiàn) AbstractEventLoopPolicy 抽象基類中定義的API。

獲取和設置策略?

可以使用下面函數(shù)獲取和設置當前進程的策略:

asyncio.get_event_loop_policy()?

返回當前進程域的策略。

asyncio.set_event_loop_policy(policy)?

policy 設置為當前進程域策略。

如果 policy 設為 None 將恢復默認策略。

策略對象?

抽象事件循環(huán)策略基類定義如下:

class asyncio.AbstractEventLoopPolicy?

異步策略的抽象基類。

get_event_loop()?

為當前上下文獲取事件循環(huán)。

返回一個實現(xiàn) AbstractEventLoop 接口的事件循環(huán)對象。

該方法永遠不應返回 None。

在 3.6 版更改.

set_event_loop(loop)?

將當前上下文的事件循環(huán)設置為 loop

new_event_loop()?

創(chuàng)建并返回一個新的事件循環(huán)對象。

該方法永遠不應返回 None。

get_child_watcher()?

獲取子進程監(jiān)視器對象。

返回一個實現(xiàn) AbstractChildWatcher 接口的監(jiān)視器對象。

該函數(shù)僅支持Unix。

set_child_watcher(watcher)?

將當前子進程監(jiān)視器設置為 watcher 。

該函數(shù)僅支持Unix。

asyncio附帶下列內置策略:

class asyncio.DefaultEventLoopPolicy?

默認的 asyncio 策略。 在 Unix 上使用 SelectorEventLoop 而在 Windows 上使用 ProactorEventLoop。

不需要手動安裝默認策略。asyncio已配置成自動使用默認策略。

在 3.8 版更改: 在 Windows 上,現(xiàn)在默認會使用 ProactorEventLoop。

class asyncio.WindowsSelectorEventLoopPolicy?

一個使用 SelectorEventLoop 事件循環(huán)實現(xiàn)的替代事件循環(huán)策略。

可用性: Windows。

class asyncio.WindowsProactorEventLoopPolicy?

使用 ProactorEventLoop 事件循環(huán)實現(xiàn)的另一種事件循環(huán)策略。

可用性: Windows。

進程監(jiān)視器?

進程監(jiān)視器允許定制事件循環(huán)如何監(jiān)視Unix子進程。具體來說,事件循環(huán)需要知道子進程何時退出。

在asyncio中子進程由 create_subprocess_exec()loop.subprocess_exec() 函數(shù)創(chuàng)建。

asyncio 定義了 AbstractChildWatcher 抽象基類,子監(jiān)視器必須要實現(xiàn)它,并具有四種不同實現(xiàn): ThreadedChildWatcher (已配置為默認使用), MultiLoopChildWatcher, SafeChildWatcherFastChildWatcher。

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

以下兩個函數(shù)可用于自定義子進程監(jiān)視器實現(xiàn),它將被asyncio事件循環(huán)使用:

asyncio.get_child_watcher()?

返回當前策略的當前子監(jiān)視器。

asyncio.set_child_watcher(watcher)?

將當前策略的子監(jiān)視器設置為 watcher 。watcher 必須實現(xiàn) AbstractChildWatcher 基類定義的方法。

備注

第三方事件循環(huán)實現(xiàn)可能不支持自定義子監(jiān)視器。對于這樣的事件循環(huán),禁止使用 set_child_watcher() 或不起作用。

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

注冊一個新的子處理回調函數(shù)。

安排 callback(pid, returncode, *args) 在進程的PID與 pid 相等時調用。指定另一個同進程的回調函數(shù)替換之前的回調處理函數(shù)。

回調函數(shù) callback 必須是線程安全。

remove_child_handler(pid)?

刪除進程PID與 pid 相等的進程的處理函數(shù)。

處理函數(shù)成功刪除時返回 True ,沒有刪除時返回 False 。

attach_loop(loop)?

給一個事件循環(huán)綁定監(jiān)視器。

如果監(jiān)視器之前已綁定另一個事件循環(huán),那么在綁定新循環(huán)前會先解綁原來的事件循環(huán)。

注意:循環(huán)有可能是 None

is_active()?

如果監(jiān)視器已準備好使用則返回 True。

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

3.8 新版功能.

close()?

關閉監(jiān)視器。

必須調用這個方法以確保相關資源會被清理。

class asyncio.ThreadedChildWatcher?

此實現(xiàn)會為每個生成的子進程啟動一具新的等待線程。

即使是當 asyncio 事件循環(huán)運行在非主 OS 線程上時它也能可靠地工作。

當處理大量子進程時不存在顯著的開銷 (每次子進程結束時為 O(1)),但當每個進程啟動一個線程時則需要額外的內存。

此監(jiān)視器會默認被使用。

3.8 新版功能.

class asyncio.MultiLoopChildWatcher?

此實現(xiàn)會在實例化時注冊一個 SIGCHLD 信號處理程序。 這可能會破壞為 SIGCHLD 信號安裝自定義處理程序的第三方代碼。

此監(jiān)視器會在收到 SIGCHLD 信號時通過顯式地輪詢每個進程來避免干擾其他代碼生成的進程。

該監(jiān)視器一旦被安裝就不會限制從不同線程運行子進程。

該解決方案是安全的,但在處理大量進程時會有顯著的開銷 (每收到一個 SIGCHLD 時為 O(n))。

3.8 新版功能.

class asyncio.SafeChildWatcher?

該實現(xiàn)會使用主線程中的活動事件循環(huán)來處理 SIGCHLD 信號。 如果主線程沒有正在運行的事件循環(huán),則其他線程無法生成子進程 (會引發(fā) RuntimeError)。

此監(jiān)視器會在收到 SIGCHLD 信號時通過顯式地輪詢每個進程來避免干擾其他代碼生成的進程。

該解決方案與 MultiLoopChildWatcher 同樣安全并同樣具有 O(N) 復雜度,但需要主線程有正在運行的事件循環(huán)才能工作。

class asyncio.FastChildWatcher?

這種實現(xiàn)直接調用 os.waitpid(-1) 來獲取所有已結束的進程,可能會中斷其它代碼洐生進程并等待它們結束。

在處理大量子監(jiān)視器時沒有明顯的開銷( O(1) 每次子監(jiān)視器結束)。

該解決方案需要主線程有正在運行的事件循環(huán)才能工作,這與 SafeChildWatcher 一樣。

class asyncio.PidfdChildWatcher?

這個實現(xiàn)會輪詢處理文件描述符 (pidfds) 以等待子進程終結。 在某些方面,PidfdChildWatcher 是一個“理想的”子進程監(jiān)視器實現(xiàn)。 它不需要使用信號或線程,不會介入任何在事件循環(huán)以外發(fā)起的進程,并能隨事件循環(huán)發(fā)起的子進程數(shù)量進行線性伸縮。 其主要缺點在于 pidfds 是 Linux 專屬的,并且僅在較近版本的核心(5.3+)上可用。

3.9 新版功能.

自定義策略?

要實現(xiàn)一個新的事件循環(huán)策略,建議子類化 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())