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

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

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

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

否则会出现RuntimeError

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

是否真的需要此锁(为什么?),或者仅是为了与线程代码兼容?

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

基本上是可选的无操作

最佳答案

答案基本上与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(),此时,等待条件的下一个使用者将获得该锁(因为它从wait()返回)。队列中要处理的项目。这并不能完全转换为基于协程的应用程序,因为协程没有线程系统遇到的等待工作完成的闲着闲事,因此,简化消费者共同合作的过程要容易得多。根据需要执行常规操作(可能需要使用信号灯来设置上限)。

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

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

关于python - 除了与threading.Condition兼容以外,asyncio.Condition中的锁还有其他用途吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51516666/

10-12 17:14