为什么condition.notify_all只唤醒一个服务员?

时间:2016-08-10 09:21:26

标签: python coroutine python-asyncio

我试图创建java的CountDownLatch

的python异步版本
class CountDownLatch:
    def __init__(self, count=1):
        if count == 0:
            raise ValueError('count should be more than zero')
        self.count = count
        self.countdown_over = aio.Condition()

    async def countdown(self):
        with await self.countdown_over:
            print('decrementing counter')
            self.count -= 1
            print('count {}'.format(self.count))
            if self.count == 0:
                print('count is zero no more waiting')
                await aio.sleep(1)
                self.countdown_over.notify_all()

    async def wait(self):
        with await self.countdown_over:
            await self.countdown_over.wait()

现在我正在尝试。

In [2]: async def g(latch):
   ...:     await latch.wait()
   ...:     print('g')
   ...:

In [3]: async def f(latch):
   ...:     print('counting down')
   ...:     await latch.countdown()
   ...:     await g(latch)
   ...:

In [4]: def run():
   ...:     latch = CountDownLatch(2)
   ...:     loop = aio.get_event_loop()
   ...:     loop.run_until_complete(aio.wait((f(latch), f(latch))))
   ...:

In [5]: import asyncio as aio

In [6]: from new.tests.test_turnovers import CountDownLatch

这是输出

counting down
decrementing counter
count 1
counting down
decrementing counter
count 0
count is zero no more waiting
g

我无法理解我在这里做错了什么。计数器创建和减少就好了。一个协程甚至被通知并继续它的任务,但第二个协议不是出于某种原因。

1 个答案:

答案 0 :(得分:1)

f1f称为第一个,让f2f称为第二个。需要注意的是,即使您使用async关键字f功能同步,直到它达到latch.wait()。因此,我们可以轻松地调试正在发生的事情:

  1. f1开火。
  2. count减少1
  3. f1输入await self.countdown_over.wait()并且上下文切换发生
  4. f2开火
  5. count减少1f2进入if条件
  6. self.countdown_over.notify_all()开火。所有服务员都会收到通知(请注意,此时只有f1)。
  7. f2输入await self.countdown_over.wait()并且上下文切换发生
  8. f1醒来并离开.wait()来电
  9. 请注意,步骤7在步骤6之后发生。因此永远不会通知f2

    通常,如果您有多个(绿色或非绿色)线程确实通知并等待(按此顺序,同步),那么它们中的至少一个将始终无法继续。