同步原語 (Synchronization Primitives)

原始碼:Lib/asyncio/locks.py


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 並回傳。

如果鎖的狀態為 unlockedRuntimeError 會被引發。

locked()

如果鎖的狀態為 locked 則回傳 True

Event

class asyncio.Event

一個事件 (event) 物件。不支援執行緒安全。

一個 asyncio 事件可以被用於通知多個有發生某些事件於其中的 asyncio 任務。

一個 Event 物件會管理一個內部旗標 (flag),它可以透過 set() 方法來被設為 true 並透過 clear() 方法來重置為 falsewait() 方法會被阻塞 (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())
async wait()

持續等待直到事件被設置。

如果事件有被設置則立刻回傳 True。否則持續阻塞直到另一個任務呼叫 set()

set()

設置事件。

所有正在等待事件被設置的任務會立即被喚醒。

clear()

清除(還原)事件。

正透過 wait() 等待的後續 Tasks 現在會持續阻塞直到 set() 方法再次被呼叫。

is_set()

如果事件有被設置則回傳 True

Condition

class asyncio.Condition(lock=None)

一個條件 (codition) 物件。不支援執行緒安全。

一個 asyncio 條件原語可以被任務用來等待某事件發生,並獲得一個共享資源的獨佔存取權。

本質上,一個 Condition 物件會結合 EventLock 的功能。多個 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)