首页 文章

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

提问于
浏览
2

我想问一下asyncio.Condition . 我不熟悉这个概念,但是从学生时代起我就知道并理解锁,信号量和队列 .

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

但是,实现和使用比这更复杂 . 等待协同程序必须首先获取与该条件关联的锁以便能够等待(并且 wait() 在等待时释放它) . 通知程序还必须获取一个能够通知()的锁 . 这会在每次操作之前产生 with 语句:

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

或者是 RuntimeError 发生者 .

我不明白这个锁的意义 . 我们需要用锁来保护什么资源?在asyncio中,事件循环中始终只能执行一个协同程序,因此没有从线程中知道的“关键部分” .

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

我的第一个想法是它的兼容性,但在这种情况下,为什么他们不保留使用时删除锁?即制作

async with condition:

基本上是一个可选的无操作 .

1 回答

  • 2

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

    条件用于表示资源可用 . 谁在等待病情,可以 use that resource until they are done with it . 要确保没有其他人可以使用该资源,您需要锁定资源:

    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() 恢复后锁定是如何释放的!在锁定被释放之前,没有其他协同例程可以继续等待相同的条件,因此通过锁定对资源的访问是独占的 . 请注意,锁定在等待时释放,因此其他协同程序可以将自己添加到队列中,但是为了最终返回锁定必须首先重新获取 .

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

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

    对于线程,所提供条件的典型用例是单个 生产环境 者,以及多个消费者都在等待 生产环境 者处理的项目 . 工作队列是共享资源, 生产环境 者获取条件锁定以将项目推入队列然后调用 notify() ,此时等待条件的下一个消费者被赋予锁定(因为它从 wait() 返回)并且可以删除要从队列中处理的项目 . 这并没有让线程系统有空闲等待工作的问题,而是根据需要简化消费者协同程序(可能是一个信号量来强加上限) .

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


    (*):事件具有与条件不同的用例,因此与没有锁定的条件有一点不同 . 一旦设置,一个事件需要明确清除,而条件'auto-clears'在使用时,并且当没有人在等待条件时永远不会'set' . 但是,如果您想在任务之间发出信号并且不需要控制对共享资源的访问,那么您可能想要一个事件 .

相关问题