2016-08-10 41 views
0

我想盡量創造Java的CountDownLatch爲什麼condition.notify_all只會喚醒一個服務員?

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

f1f叫作第一個,讓f2f叫作第二個。應該注意的是,即使您已經使用async關鍵字f功能是同步,直到它遇到latch.wait()。因此,我們實際上可以輕鬆地調試發生了什麼:

  1. f1火災。
  2. count1
  3. f1降低進入await self.countdown_over.wait()上下文切換發生
  4. f2火災
  5. count1降低,f2進入if條件
  6. self.countdown_over.notify_all()火災。所有服務員都會收到通知(請注意,當時只有f1)。
  7. f2進入await self.countdown_over.wait()上下文切換發生
  8. f1醒來並離開.wait()呼叫

注意,步驟7發生步驟6。因此f2從不通知。

通常,如果您有多個(綠色或不綠色)線程通知並等待(按此順序,同步),那麼至少其中一個線程將始終無法繼續。