策略?

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

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

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

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

獲取和設(shè)置策略?

可以使用下面函數(shù)獲取和設(shè)置當(dāng)前進(jìn)程的策略:

asyncio.get_event_loop_policy()?

返回當(dāng)前進(jìn)程域的策略。

asyncio.set_event_loop_policy(policy)?

policy 設(shè)置為當(dāng)前進(jìn)程域策略。

如果 policy 設(shè)為 None 將恢復(fù)默認(rèn)策略。

策略對象?

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

class asyncio.AbstractEventLoopPolicy?

異步策略的抽象基類。

get_event_loop()?

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

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

該方法永遠(yuǎn)不應(yīng)返回 None。

在 3.6 版更改.

set_event_loop(loop)?

將當(dāng)前上下文的事件循環(huán)設(shè)置為 loop 。

new_event_loop()?

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

該方法永遠(yuǎn)不應(yīng)返回 None。

get_child_watcher()?

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

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

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

set_child_watcher(watcher)?

將當(dāng)前子進(jìn)程監(jiān)視器設(shè)置為 watcher

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

asyncio附帶下列內(nèi)置策略:

class asyncio.DefaultEventLoopPolicy?

默認(rèn)的 asyncio 策略。 在 Unix 上使用 SelectorEventLoop 而在 Windows 上使用 ProactorEventLoop。

不需要手動(dòng)安裝默認(rèn)策略。asyncio已配置成自動(dòng)使用默認(rèn)策略。

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

class asyncio.WindowsSelectorEventLoopPolicy?

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

可用性: Windows。

class asyncio.WindowsProactorEventLoopPolicy?

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

可用性: Windows。

進(jìn)程監(jiān)視器?

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

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

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

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

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

asyncio.get_child_watcher()?

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

asyncio.set_child_watcher(watcher)?

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

備注

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

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

注冊一個(gè)新的子處理回調(diào)函數(shù)。

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

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

remove_child_handler(pid)?

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

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

attach_loop(loop)?

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

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

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

is_active()?

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

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

3.8 新版功能.

close()?

關(guān)閉監(jiān)視器。

必須調(diào)用這個(gè)方法以確保相關(guān)資源會(huì)被清理。

class asyncio.ThreadedChildWatcher?

此實(shí)現(xiàn)會(huì)為每個(gè)生成的子進(jìn)程啟動(dòng)一具新的等待線程。

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

當(dāng)處理大量子進(jìn)程時(shí)不存在顯著的開銷 (每次子進(jìn)程結(jié)束時(shí)為 O(1)),但當(dāng)每個(gè)進(jìn)程啟動(dòng)一個(gè)線程時(shí)則需要額外的內(nèi)存。

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

3.8 新版功能.

class asyncio.MultiLoopChildWatcher?

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

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

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

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

3.8 新版功能.

class asyncio.SafeChildWatcher?

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

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

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

class asyncio.FastChildWatcher?

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

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

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

class asyncio.PidfdChildWatcher?

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

3.9 新版功能.

自定義策略?

要實(shí)現(xiàn)一個(gè)新的事件循環(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())