策略?
事件循環(huán)策略是各個(gè)進(jìn)程的全局對(duì)象 ,它控制事件循環(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ù)的行為。
策略對(duì)象應(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)策略。
策略對(duì)象?
抽象事件循環(huán)策略基類定義如下:
- class asyncio.AbstractEventLoopPolicy?
異步策略的抽象基類。
- get_event_loop()?
為當(dāng)前上下文獲取事件循環(huán)。
返回一個(gè)實(shí)現(xiàn)
AbstractEventLoop
接口的事件循環(huán)對(duì)象。該方法永遠(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)對(duì)象。
該方法永遠(yuǎn)不應(yīng)返回
None
。
- get_child_watcher()?
獲取子進(jìn)程監(jiān)視器對(duì)象。
返回一個(gè)實(shí)現(xiàn)
AbstractChildWatcher
接口的監(jiān)視器對(duì)象。該函數(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
, SafeChildWatcher
和 FastChildWatcher
。
請(qǐng)參閱 子進(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)視器。對(duì)于這樣的事件循環(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())