事件迴圈¶
原始碼: Lib/asyncio/events.py、Lib/asyncio/base_events.py
前言
事件迴圈是每個 asyncio 應用程式的核心。事件迴圈執行非同步任務和回呼、執行網路 IO 操作並啟動子行程。
應用程式開發人員通常應使用高階的 asyncio 函式,例如 asyncio.run(),並且很少需要參照事件迴圈物件或呼叫其方法。本節主要針對那些需要更細粒度控制事件迴圈行為的低階程式碼、函式庫和框架的作者。
取得事件迴圈
以下的低階函式可用於取得、設置或建立事件迴圈:
- asyncio.get_running_loop()¶
在目前作業系統執行緒中回傳正在運行的事件迴圈。
如果沒有運行的事件迴圈,則引發
RuntimeError。此函式只能從協程或回呼函式中呼叫。
在 3.7 版被加入.
- asyncio.get_event_loop()¶
取得目前的事件迴圈。
當從協程或回呼函式呼叫此函式(例如,使用 call_soon 或類似的 API 於排程呼叫),此函式將永遠回傳正在運行的事件迴圈。
如果沒有設定正在運行的事件迴圈,該函式將回傳
get_event_loop_policy().get_event_loop()呼叫的結果。由於此函式具有相當複雜的行為(尤其是在使用自訂事件迴圈策略時),在協程和回呼函式中,建議使用
get_running_loop()函式,而不是get_event_loop()。如上所述,可以考慮使用高階的
asyncio.run()函式,而不是使用這些較低階的函式手動建立和關閉事件迴圈。在 3.14 版的變更: 如果沒有目前的事件迴圈,則引發
RuntimeError。備註
asyncio的政策系統已被棄用,並將於 Python 3.16 中移除;此後,此函式將回傳目前執行中的事件迴圈(若存在),否則將回傳由set_event_loop()設定的迴圈。
- asyncio.set_event_loop(loop)¶
將 loop 設置為目前 OS 執行緒的目前事件迴圈。
- asyncio.new_event_loop()¶
建立並回傳新的事件迴圈物件。
請注意 get_event_loop()、set_event_loop() 和 new_event_loop() 函式的行為可以透過設定自訂事件迴圈策略進行調整。
目錄
本頁文件包含以下章節:
事件迴圈方法章節是事件迴圈 API 們的參照文件;
回呼處理章節記錄了從排程方法(如
loop.call_soon()和loop.call_later())回傳的Handle和TimerHandle實例;Server 物件章節記錄了從事件迴圈方法(如
loop.create_server())回傳的資料型別;事件迴圈實作章節記錄了
SelectorEventLoop和ProactorEventLoop類別;範例章節展示了如何使用一些事件迴圈 API。
事件迴圈方法¶
事件迴圈提供以下低階 API:
啟動和停止迴圈¶
- loop.run_until_complete(future)¶
運行直到 future (一個
Future實例)完成。如果引數是協程物件,則它將被隱式排程為
asyncio.Task運行。回傳 Future 的結果或引發其例外。
- loop.run_forever()¶
運行事件迴圈直到
stop()被呼叫。如果在呼叫
run_forever()之前呼叫stop(),則迴圈將使用超時為零的方式輪詢 I/O 選擇器,運行所有回應 I/O 事件(以及已經排程的事件)的回呼,然後退出。如果在
run_forever()運行時呼叫stop(),則迴圈將運行目前批次的回呼函式,然後退出。請注意,由回呼函式排程的新回呼在此情況下不會運行;而是在下次呼叫run_forever()或run_until_complete()時運行。
- loop.stop()¶
停止事件迴圈。
- loop.is_running()¶
如果事件迴圈目前正在運行,則回傳
True。
- loop.is_closed()¶
如果事件迴圈已關閉,則回傳
True。
- loop.close()¶
關閉事件迴圈。
不得於迴圈運行中呼叫此函式。將丟棄任何待處理的回呼。
此方法清除所有佇列並關閉執行器,但不等待執行器完成。
此方法是冪等且不可逆的。在事件迴圈關閉後不應呼叫其他方法。
- async loop.shutdown_asyncgens()¶
排程所有目前打開的非同步產生器物件使用
aclose()呼叫來關閉。呼叫此方法後,如果疊代新的非同步產生器,事件迴圈將發出警告。應該使用此方法可靠地完成所有已排程的非同步產生器。請注意,使用
asyncio.run()時不需要呼叫此函式。範例:
try: loop.run_forever() finally: loop.run_until_complete(loop.shutdown_asyncgens()) loop.close()
在 3.6 版被加入.
- async loop.shutdown_default_executor(timeout=None)¶
排程預設執行器的關閉,並等待它加入
ThreadPoolExecutor中的所有執行緒。一旦呼叫了此方法,使用預設執行器與loop.run_in_executor()將引發RuntimeError。timeout 參數指定執行器完成加入所需的時間(以
float秒為單位)。預設情況下為None,不會限制執行器所花費的時間。如果達到 timeout,將發出
RuntimeWarning警告,預設執行器將立即終止,不等待其執行緒完成加入。備註
使用
asyncio.run()時請勿呼叫此方法,因為後者會自動處理預設執行器的關閉。在 3.9 版被加入.
在 3.12 版的變更: 加入 timeout 參數。
排程回呼函式¶
- loop.call_soon(callback, *args, context=None)¶
在事件迴圈的下一次疊代中排程以 args 引數呼叫 callback callback。
回傳
asyncio.Handle的實例,稍後可以用於取消回呼函式。回呼函式按照其註冊的順序呼叫。每個回呼函式將被呼叫恰好一次。
選用的僅限關鍵字引數 context 指定了要給 callback 執行的自訂
contextvars.Context。當未提供 context 時,回呼函式使用目前情境。與
call_soon_threadsafe()不同,此方法不是執行緒安全的。
- loop.call_soon_threadsafe(callback, *args, context=None)¶
這是
call_soon()的執行緒安全變體。當從另一個執行緒排程回呼函式時,必須使用此函式,因為call_soon()不是執行緒安全的。This function is safe to be called from a reentrant context or signal handler, however, it is not safe or fruitful to use the returned handle in such contexts.
如果在已關閉的迴圈上呼叫,則引發
RuntimeError。在主應用程式關閉時,這可能發生在次要執行緒上。請參閱文件的並行和多執行緒部分。
在 3.7 版的變更: 新增了 context 僅限關鍵字參數。詳細資訊請參閱 PEP 567。
備註
大多數 asyncio 排程函式不允許傳遞關鍵字引數。要傳遞關鍵字引數,請使用 functools.partial():
# 將會排程 "print("Hello", flush=True)"
loop.call_soon(
functools.partial(print, "Hello", flush=True))
通常使用 partial 物件比使用 lambda 更方便,因為 asyncio 可以在除錯和錯誤訊息中更好地呈現 partial 物件。
排程延遲的回呼函式¶
事件迴圈提供為回呼函式排程在將來某個時間點才呼叫的機制。事件迴圈使用了單調時鐘來追蹤時間。
- loop.call_later(delay, callback, *args, context=None)¶
排程 callback 在給定的 delay 秒數後呼叫(可以是整數或浮點數)。
回傳
asyncio.TimerHandle的實例,可用於取消回呼函式。callback 將只被呼叫恰好一次。如果有兩個回呼函式被排程在完全相同的時間,則其呼叫順序是不定的。
可選的位置引數 args 將在回呼函式被呼叫時傳遞給它。使用
functools.partial()來傳遞關鍵字引數給 callback。可選的僅限關鍵字 context 引數允許為 callback 指定自訂的
contextvars.Context以提供運行。當未提供 context 時,將使用目前情境。備註
For performance, callbacks scheduled with
loop.call_later()may run up to one clock-resolution early (seetime.get_clock_info('monotonic').resolution).在 3.7 版的變更: 新增了 context 僅限關鍵字參數。詳細資訊請參閱 PEP 567。
在 3.8 版的變更: 在 Python 3.7 及更早版本中,使用預設事件迴圈實作時,delay 不能超過一天。這在 Python 3.8 中已經修復。
- loop.call_at(when, callback, *args, context=None)¶
排程 callback 在給定的絕對時間戳 when (整數或浮點數)處呼叫,使用與
loop.time()相同的時間參照。此方法的行為與
call_later()相同。回傳
asyncio.TimerHandle的實例,可用於取消回呼函式。備註
For performance, callbacks scheduled with
loop.call_at()may run up to one clock-resolution early (seetime.get_clock_info('monotonic').resolution).在 3.7 版的變更: 新增了 context 僅限關鍵字參數。詳細資訊請參閱 PEP 567。
在 3.8 版的變更: 在 Python 3.7 及更早版本中,使用預設事件迴圈實作時,when 和目前時間之間的差值不能超過一天。這在 Python 3.8 中已經修復。
備註
在 3.8 版的變更: 在 Python 3.7 及更早版本中,超時(相對 delay 或絕對 when)不應超過一天。這在 Python 3.8 中已經修復。
也參考
函式 asyncio.sleep()。
建立 Futures 和 Tasks¶
- loop.create_future()¶
建立附加到事件迴圈的
asyncio.Future物件。這是在 asyncio 中建立 Futures 的首選方式。這允許第三方事件迴圈提供 Future 物件的替代實作(具有更好的性能或儀器計測表現)。
在 3.5.2 版被加入.
- loop.create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)¶
-
第三方事件迴圈可以使用其自己的
Task子類別以實現互操作性(interoperability)。在這種情況下,結果類型是Task的子類別。The full function signature is largely the same as that of the
Taskconstructor (or factory) - all of the keyword arguments to this function are passed through to that interface.如果提供了 name 引數且不為
None,則將其設置為任務的名稱,使用Task.set_name()。可選的僅限關鍵字 context 引數允許為 coro 指定自訂的
contextvars.Context以提供運行。當未提供 context 時,將建立目前情境的副本。An optional keyword-only eager_start argument allows specifying if the task should execute eagerly during the call to create_task, or be scheduled later. If eager_start is not passed the mode set by
loop.set_task_factory()will be used.在 3.8 版的變更: 加入 name 參數。
在 3.11 版的變更: 加入 context 參數。
在 3.13.3 版的變更: Added
kwargswhich passes on arbitrary extra parameters, includingnameandcontext.在 3.13.4 版的變更: Rolled back the change that passes on name and context (if it is None), while still passing on other arbitrary keyword arguments (to avoid breaking backwards compatibility with 3.13.3).
在 3.14 版的變更: All kwargs are now passed on. The eager_start parameter works with eager task factories.
- loop.set_task_factory(factory)¶
設置將由
loop.create_task()使用的任務工廠。如果 factory 為
None,將設置預設的任務工廠。否則,factory 必須是一個具有匹配簽名(loop, coro, **kwargs)的 callable,其中 loop 是有效事件迴圈的參照、coro 是一個協程物件。該可呼叫物件必須傳遞所有 kwargs 並回傳一個與asyncio.Task相容的物件。在 3.13.3 版的變更: Required that all kwargs are passed on to
asyncio.Task.在 3.13.4 版的變更: name is no longer passed to task factories. context is no longer passed to task factories if it is
None.在 3.14 版的變更: name and context are now unconditionally passed on to task factories again.
- loop.get_task_factory()¶
回傳任務工廠,如果使用預設任務工廠則回傳
None。
打開網路連線¶
- async loop.create_connection(protocol_factory, host=None, port=None, *, ssl=None, family=0, proto=0, flags=0,