除了与threading.Condition兼容以外,asyncio.Condition中的锁还有其他用途吗?

时间:2018-07-25 10:30:43

标签: python python-asyncio

我想问一下asyncio.Condition。我对这个概念不熟悉,但是自从我学习以来,我就知道并理解锁,信号量和队列。

this example就找不到很好的解释或典型用例。我看着源头。核心功能是通过期货的FIFO实现的。每个等待的协程都会添加一个新的未来并等待它。另一个协程可以调用notify(),它从FIFO设置一个或多个更多期货的结果,并唤醒相同数量的等待协程。到目前为止非常简单。

但是,实现和用法比这更复杂。等待的协程必须首先获取与条件相关联的锁,以便能够等待(wait()在等待时将其释放)。通知者还必须获取一个锁才能通知()。这会导致在每次操作之前出现with条语句:

async with condition:
    # condition operation (wait or notify)

RuntimeError个出现者。

我不知道拥有此锁的意义。我们需要用锁保护什么资源?在异步中,在事件循环中始终只能执行一个协程,没有从线程已知的“关键部分”。

真的需要这个锁吗(为什么?)还是仅与线程代码兼容?

我的第一个想法是出于兼容性的考虑,但是在这种情况下,为什么他们在保留用法的同时不移除锁呢?即制作

async with condition:

基本上是可选的无操作

1 个答案:

答案 0 :(得分:3)

答案基本上与threading.Condition vs threading.Event相同; 没有锁定的条件是事件,而不是条件(*)

条件用于表示资源可用。任何等待条件的人都可以使用该资源,直到完成处理为止。为了确保没有其他人可以使用该资源,您需要锁定该资源:

resource = get_some_resource()

async with resource.condition:
    await resource.condition.wait()
    # this resource is mine, no-one will touch it
    await resource.do_something_async()

# lock released, resource is available again for the next user

请注意,wait()恢复后如何解除锁定!在释放锁之前,没有其他等待相同条件的协同例程可以继续进行,通过该锁可以独占访问资源。请注意,在等待时释放了锁,因此其他协程可以将其添加到队列中,但是要使wait()最终返回锁,必须首先重新获取。

如果您不需要协调对共享资源的访问,请使用一个事件;条件基本上是将锁和事件组合成一个原语,从而避免了常见的实现陷阱。

请注意,多个条件可以共享锁。这可以让您发信号通知特定阶段,其他协程可以等待该特定阶段到达。共享锁可以协调对单个资源的访问,但是在每个阶段启动时会发出不同的信号。

对于线程,所提供条件的典型用例是单个生产者的用例,而多个消费者都在等待生产者要处理的项目。工作队列是共享资源,生产者获取条件锁以将项目推送到队列中,然后调用notify(),此时,等待条件的下一个使用者将获得该锁(因为它从{返回{1}}),并且可以从队列中删除该项目以进行处理。这并不能完全转换为基于协程的应用程序,因为协程没有线程系统遇到的等待工作完成的闲着闲事,因此,简化消费者共同合作的过程要容易得多。根据需要执行例行程序(可能使用信号灯来设置上限)。

也许更好的例子是aioimaplib library,它完全支持IMAP4事务。这些事务是异步的,但是您需要有权访问共享连接资源。因此,库使用单个Condition对象和wait()等待特定状态到达,从而为等待该事务状态的协程提供独占连接访问权限。


(*):事件的使用情况与条件不同,因此行为与未锁定的条件略有不同。设置后,需要明确清除事件,而条件在使用时会自动清除,而在没有人等待该条件时则永远不会设置。但是,如果您想在任务之间发信号,而无需控制对共享资源的访问,那么您可能想要一个事件。