Skip to main content

18.5.7. 同步原语

锁:

信号量:

asyncio锁API被设计为接近 threading 模块(LockEventConditionSemaphoreBoundedSemaphore)的类,但它没有 timeout 参数。 asyncio.wait_for() 功能可用于在超时后取消任务。

18.5.7.1. 锁

18.5.7.1.1. 锁

class asyncio.Lock(*, loop=None)

原语锁对象。

原语锁是同步原语,它不是由特定协同程序在锁定时拥有的。原始锁处于“锁定”或“解锁”两种状态之一。

它是在解锁状态下创建的。它有两个基本方法,acquire()release()。当状态解锁时,acquire()将状态更改为锁定并立即返回。当状态被锁定时,acquire()块直到对另一个协程中的release()的调用将其改变为解锁,然后acquire()调用将其重置为锁定并返回。 release()方法只应在锁定状态下调用;它将状态更改为已解锁并立即返回。如果尝试释放已解锁的锁,则会引发 RuntimeError

当在acquire()中阻塞了多个协同程序以等待状态转为解锁时,只有一个协程在release()调用将状态重置为未锁定时进行;正在处理在acquire()中被阻塞的第一协同程序。

acquire() 是协程,应该使用 yield from 调用。

锁也支持上下文管理协议。 (yield from lock) 应该用作上下文管理器表达式。

这个类是 不是线程安全

用法:

lock = Lock()
...
yield from lock
try:
    ...
finally:
    lock.release()

上下文管理器使用:

lock = Lock()
...
with (yield from lock):
    ...

可以测试锁定对象的锁定状态:

if not lock.locked():
    yield from lock
else:
    # lock is acquired
    ...
locked()

如果获取锁定,则返回 True

coroutine acquire()

获取锁。

此方法阻塞,直到锁被解锁,然后将其设置为锁定并返回 True

这种方法是 协同

release()

释放锁。

当锁被锁定时,将其重置为解锁,然后返回。如果任何其他协同程序被阻塞等待锁定解锁,则只允许其中一个继续。

当在解锁的锁上被调用时,RuntimeError 被引发。

没有返回值。

18.5.7.1.2. 事件

class asyncio.Event(*, loop=None)

事件实现,异步等同于 threading.Event

实现事件对象的类。事件管理可以使用 set() 方法设置为true并使用 clear() 方法重置为false的标志。 wait() 方法阻塞,直到标志为真。该标志最初为假。

这个类是 不是线程安全

clear()

将内部标志重置为false。随后,调用 wait() 的协程将阻塞,直到调用 set() 将内部标志重新设置为true。

is_set()

返回 True 当且仅当所述内部标志为真。

set()

将内部标志设置为true。所有协程,等待它成为真正的觉醒。一旦标志为真,调用 wait() 的协程将不会阻塞。

coroutine wait()

阻塞直到内部标志为真。

如果内部标志在入口时为真,则立即返回 True。否则,阻塞直到另一个协同程序调用 set() 将标志设置为true,然后返回 True

这种方法是 协同

18.5.7.1.3. 条件

class asyncio.Condition(lock=None, *, loop=None)

A条件实现,异步等同于 threading.Condition

这个类实现条件变量对象。条件变量允许一个或多个协同程序等待,直到它们被另一个协程通知。

如果给出了 lock 参数而不是 None,它必须是一个 Lock 对象,并且它被用作底层锁。否则,将创建一个新的 Lock 对象并将其用作基础锁。

这个类是 不是线程安全

coroutine acquire()

获取底层锁。

此方法阻塞,直到锁被解锁,然后将其设置为锁定并返回 True

这种方法是 协同

notify(n=1)

默认情况下,唤醒一个等待此条件的协程(如果有)。如果调用协调程序在调用此方法时未获取锁定,则会引发 RuntimeError

该方法最多唤醒等待条件变量的协程的 n;如果没有协程正在等待,它是一个无操作。

注解

唤醒的协程实际上不会从其 wait() 调用返回,直到它可以重新获取锁。由于 notify() 不释放锁,其调用者应该。

locked()

如果获取了基础锁,则返回 True

notify_all()

唤醒所有协程,等待此条件。此方法的行为像 notify(),但唤醒所有等待协同而不是一个。如果在调用此方法时调用协同程序尚未获取锁,则会引发 RuntimeError

release()

释放底层锁。

当锁被锁定时,将其重置为解锁,然后返回。如果任何其他协同程序被阻塞等待锁定解锁,则只允许其中一个继续。

当在解锁的锁上被调用时,RuntimeError 被引发。

没有返回值。

coroutine wait()

等待直到通知。

如果调用协调程序在调用此方法时未获取锁定,则会引发 RuntimeError

此方法释放底层锁,然后阻塞,直到它被另一个协同程序中的相同条件变量的 notify()notify_all() 调用唤醒。一旦被唤醒,它重新获取锁并返回 True

这种方法是 协同

coroutine wait_for(predicate)

等待一个谓词变为true。

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

这种方法是 协同

18.5.7.2. 信号量

18.5.7.2.1. 信号

class asyncio.Semaphore(value=1, *, loop=None)

信号量实现。

信号量管理内部计数器,该内部计数器由每个 acquire() 调用递减并且由每个 release() 调用递增。计数器永远不会低于零;当 acquire() 发现它是零时,它阻塞,等待一些其他协同程序调用 release()

Semaphores还支持上下文管理协议。

可选参数给出内部计数器的初始值;它默认为 1。如果给定的值小于 0,则产生 ValueError

这个类是 不是线程安全

coroutine acquire()

获取信号量。

如果内部计数器在输入时大于零,则将其减1并立即返回 True。如果在入口处为零,则阻塞,等待直到一些其它协同程序调用 release() 使其大于 0,然后返回 True

这种方法是 协同

locked()

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

release()

释放信号量,使内部计数器递增1。当它在入口为零,并且另一个协同程序等待它再次变得大于零时,唤醒该协同程序。

18.5.7.2.2. BoundedSemaphore

class asyncio.BoundedSemaphore(value=1, *, loop=None)

有界信号量实现。继承自 Semaphore

如果它将增加高于初始值的值,则在 release() 中提高 ValueError