策略¶
事件迴圈策略是一個全域性物件,用於獲取和設定當前事件迴圈,以及建立新的事件迴圈。預設策略可以透過替換為內建的替代方案來使用不同的事件迴圈實現,或者用可以覆蓋這些行為的自定義策略來替換。
策略物件獲取和設定每個上下文的單獨事件迴圈。預設情況下,這是每個執行緒的,但自定義策略可能會以不同的方式定義上下文。
自定義事件迴圈策略可以控制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
(配置為預設使用)、MultiLoopChildWatcher
、SafeChildWatcher
和 FastChildWatcher
。
另請參閱 子程序和執行緒 部分。
以下兩個函式可用於自定義 asyncio 事件迴圈使用的子程序監視器實現
- asyncio.get_child_watcher()¶
返回當前策略的當前子監視器。
在 3.12 版本中棄用。
- asyncio.set_child_watcher(watcher)¶
將當前策略的當前子監視器設定為 watcher。watcher 必須實現
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())