同步原语

源代码: Lib/asyncio/locks.py


异步同步原语的设计与 threading 有两个重要注意事项的模块:

  • 异步原语不是线程安全的,因此不应将它们用于OS线程同步(使用 threading 为此);

  • 这些同步原语的方法不接受 timeout 参数;使用 asyncio.wait_for() 函数执行超时操作。

Asyncio具有以下基本同步原语:


class 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()
coroutine acquire()

获取锁。

此方法等待直到锁 解锁 将它设置为 锁定的 回报 True .

当一个以上的协程被阻塞时 acquire() 等待锁被解锁,最终只有一个协同程序进行。

获取锁是 fair :继续进行的协程将是第一个开始等待锁的协程。

release()

释放锁。

当锁是 锁定的 将其重置为 解锁 然后回来。

如果锁是 解锁 ,A RuntimeError 提高了。

locked()

返回 True 如果锁是 锁定的 .

事件

class asyncio.Event

事件对象。不是线程安全的。

Asyncio事件可用于通知多个Asyncio任务发生了某些事件。

事件对象管理一个内部标志,该标志可以设置为 true 使用 set() 方法,并重置为 错误 使用 clear() 方法。这个 wait() 方法会一直阻塞,直到将标志设置为 true 。该标志设置为 错误 最初是这样的。

例子::

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())
coroutine wait()

等待事件设置完毕。

如果设置了事件,则返回 True 马上就去。否则挡路会一直呼叫到另一个任务 set()

set()

设置事件。

等待事件设置的所有任务都将立即唤醒。

clear()

清除(取消设置)事件。

等待中的任务 wait() 现在挡路会一直持续到 set() 方法被再次调用。

is_set()

返回 True 如果事件已设置。

条件

class asyncio.Condition(lock=None)

条件对象。不是线程安全的。

任务可以使用asyncio条件原语等待某个事件发生,然后以独占方式访问共享资源。

实际上,条件对象结合了 Event 和A Lock .可以让多个条件对象共享一个锁,这允许在对共享资源的特定状态感兴趣的不同任务之间协调对共享资源的独占访问。

可选的 lock 参数必须是 Lock 对象或 None . 在后一种情况下,会自动创建一个新的锁对象。

使用条件的首选方法是 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()
coroutine acquire()

获取基础锁。

此方法等待,直到基础锁 解锁 将它设置为 锁定的 回报 True .

notify(n=1)

最多唤醒 n 等待此条件的任务(默认为1)。如果没有任务等待,则该方法为no op。

必须先获取锁,然后才能调用此方法并在不久后释放。如果使用 解锁 锁定A RuntimeError 出现错误。

locked()

返回 True 如果获取了基础锁。

notify_all()

唤醒在此条件下等待的所有任务。

这种方法的作用就像 notify() ,但唤醒所有等待的任务。

必须先获取锁,然后才能调用此方法并在不久后释放。如果使用 解锁 锁定A RuntimeError 出现错误。

release()

释放基础锁。

在未锁定的锁上调用时, RuntimeError 提高了。

coroutine wait()

等待通知。

如果调用此方法时调用任务未获取锁,则 RuntimeError 提高了。

此方法释放基础锁,然后阻塞,直到被 notify()notify_all() 调用。一旦被唤醒,条件将重新获取其锁,此方法将返回 True .

coroutine wait_for(predicate)

等待谓词变为 true .

谓词必须是可调用的,其结果将被解释为布尔值。最终值是返回值。

Semaphore

class asyncio.Semaphore(value=1)

信号量对象。不是线程安全的。

信号量管理一个内部计数器,该计数器由每个计数器递减 acquire() 调用并递增 release() 调用。计数器永远不能低于零;何时 acquire() 发现它是零,它会阻塞,等待一些任务调用 release() .

可选的 value 参数提供内部计数器的初始值 (1 默认情况下)。如果给定值小于 0ValueError 提高了。

使用信号量的首选方法是 async with 声明:

sem = asyncio.Semaphore(10)

# ... later
async with sem:
    # work with shared resource

相当于:

sem = asyncio.Semaphore(10)

# ... later
await sem.acquire()
try:
    # work with shared resource
finally:
    sem.release()
coroutine acquire()

获取信号量。

如果内部计数器大于零,则将其递减一并返回 True 立即。如果是零,等待直到 release() 被调用并返回 True .

locked()

返回 True 如果不能立即获取信号量。

release()

释放一个信号量,将内部计数器递增一个。无法唤醒等待获取信号量的任务。

不像 BoundedSemaphoreSemaphore 允许制造更多 release() 调用比 acquire() 调用。

BoundedSemaphore

class asyncio.BoundedSemaphore(value=1)

有界信号量对象。不是线程安全的。

有界信号量是 Semaphore 提出一个 ValueError 在里面 release() 如果它使内部计数器高于初始计数器 value .


在 3.9 版更改: 使用获取锁 await lockyield from lock 和/或 with 陈述 (with await lockwith (yield from lock) )已删除。使用 async with lock 相反。