同步原語 (Synchronization Primitives)¶
asyncio 的同步原語被設計成和那些 threading 模組 (module) 中的同名物件相似,但有兩個重要的限制條件:
asyncio 原語並不支援執行緒安全 (thread-safe),因此他們不可被用於 OS 執行緒同步化(請改用
threading);這些同步原語的方法 (method) 並不接受 timeout 引數;要達成有超時 (timeout) 設定的操作請改用
asyncio.wait_for()函式。
asyncio 有以下基礎同步原語:
Lock¶
- class asyncio.Lock¶
實作了一個給 asyncio 任務 (task) 用的互斥鎖 (mutex lock)。不支援執行緒安全。
一個 asyncio 的鎖可以用來確保一個共享資源的存取權被獨佔。
使用 Lock 的推薦方式是透過
async with陳述式:lock = asyncio.Lock() # ... later async with lock: # access shared state
這等價於:
lock = asyncio.Lock() # ... later await lock.acquire() try: # access shared state finally: lock.release()
在 3.10 版的變更: 移除
loop參數。- async acquire()¶
獲得鎖。
此方法會持續等待直到鎖的狀態成為 unlocked,並將其設置為 locked 和回傳
True。當多於一個的協程 (coroutine) 在
acquire()中等待解鎖而被阻塞,最終只會有其中的一個被處理。鎖的取得方式是公平的:被處理的協程會是最早開始等待解鎖的那一個。
- release()¶
釋放鎖。
如果鎖的狀態為 locked 則將其重置為 unlocked 並回傳。
如果鎖的狀態為 unlocked 則
RuntimeError會被引發。
- locked()¶
如果鎖的狀態為 locked 則回傳
True。
Event¶
- class asyncio.Event¶
一個事件 (event) 物件。不支援執行緒安全。
一個 asyncio 事件可以被用於通知多個有發生某些事件於其中的 asyncio 任務。
一個 Event 物件會管理一個內部旗標 (flag),它可以透過
set()方法來被設為 true 並透過clear()方法來重置為 false。wait()方法會被阻塞 (block) 直到該旗標被設為 true。該旗標初始設置為 false。在 3.10 版的變更: 移除
loop參數。範例:
async def waiter(event): print('waiting for it ...') await event.wait() print('... got it!') async def main(): # Create an Event object. event = asyncio.Event() # Spawn a Task to wait until 'event' is set. waiter_task = asyncio.create_task(waiter(event)) # Sleep for 1 second and set the event. await asyncio.sleep(1) event.set() # Wait until the waiter task is finished. await waiter_task asyncio.run(main())
- set()¶
設置事件。
所有正在等待事件被設置的任務會立即被喚醒。
- is_set()¶
如果事件有被設置則回傳
True。
Condition¶
- class asyncio.Condition(lock=None)¶
一個條件 (codition) 物件。不支援執行緒安全。
一個 asyncio 條件原語可以被任務用來等待某事件發生,並獲得一個共享資源的獨佔存取權。
本質上,一個 Condition 物件會結合
Event和Lock的功能。多個 Condition 物件共享一個 Lock 是有可能發生的,這能夠協調關注同一共享資源的不同狀態以取得其獨佔存取權的多個任務。可選的 lock 引數必須是一個
Lock物件或者為None。如為後者則一個新的 Lock 物件會被自動建立。在 3.10 版的變更: 移除
loop參數。使用 Condition 的推薦方式是透過
async with陳述式:cond = asyncio.Condition() # ... later async with cond: await cond.wait()
這等價於:
cond = asyncio.Condition() # ... later await cond.acquire() try: await cond.wait() finally: cond.release()
- async acquire()¶
取得底層的鎖。
此方法會持續等待直到底層的鎖為 unlocked,並將其設為 locked 並回傳
True。
- notify(n=1)¶
喚醒至多 n 個正在等待此條件的任務(預設為 1),如果少於 n 個任務則全部被喚醒。
在此方法被呼叫前必須先獲得鎖,並在之後立刻將其釋放。如果呼叫於一個 unlocked 的鎖則
RuntimeError錯誤會被引發。
- locked()¶
如果已取得底層的鎖則回傳
True。
- notify_all()¶
喚醒所有正在等待此條件的任務。
這個方法的行為就像
notify(),但會喚醒所有正在等待的任務。在此方法被呼叫前必須先獲得鎖,並在之後立刻將其釋放。如果呼叫於一個 unlocked 的鎖則
RuntimeError錯誤會被引發。
- release()¶
釋放底層的鎖。
當叫用於一個未被解開的鎖之上時,會引發一個
RuntimeError。
- async wait()¶
持續等待直到被通知 (notify)。
當此方法被呼叫時,如果呼叫它的任務還沒有取得鎖的話,
RuntimeError會被引發。此方法會釋放底層的鎖,然後持續阻塞直到被
notify()或notify_all()的呼叫所喚醒。一但被喚醒,Condition 會重新取得該鎖且此方法會回傳True。Note that a task may return from this call spuriously, which is why the caller should always re-check the state and be prepared to
wait()again. For this reason, you may prefer to usewait_for()instead.
- async wait_for(predicate)