2015-04-06 74 views
8

我想實現從標準輸入傳遞數據給協程的一個簡單的想法:的Python ASYNCIO:讀者回調和協程通信

import asyncio 
import sys 

event = asyncio.Event() 

def handle_stdin(): 
    data = sys.stdin.readline() 
    event.data = data # NOTE: data assigned to the event object 
    event.set() 

@asyncio.coroutine 
def tick(): 
    while 1: 
     print('Tick') 
     yield from asyncio.sleep(1) 

     if event.is_set(): 
      data = event.data # NOTE: data read from the event object 
      print('Data received: {}'.format(data)) 
      event.clear() 

def main(): 
    loop = asyncio.get_event_loop() 
    loop.add_reader(sys.stdin, handle_stdin) 
    loop.run_until_complete(tick())  

if __name__ == '__main__': 
    main() 

此代碼工作正常,但是它的一個簡化版本,帶有可變而不是Event對象的作品太:

data = None 

def handle_stdin(): 
    global data 
    data = sys.stdin.readline() 

@asyncio.coroutine 
def tick(): 
    while 1: 
     print('Tick') 
     yield from asyncio.sleep(1) 

     global data 
     if data is not None: 
      print('Data received: {}'.format(data)) 
      data = None 

我的問題是:是Event的方法正確嗎?還是有更好的方法與另一個asyncio對象來處理這種問題? 然後,如果與Event的方法是好的,使用變量是否也很好?

謝謝。

回答

12

我覺得asyncio.Queue是這種生產者/消費者的關係更適合:

import asyncio 
import sys 

queue = asyncio.Queue() 

def handle_stdin(): 
    data = sys.stdin.readline() 
    asyncio.async(queue.put(data)) # Queue.put is a coroutine, so you can't call it directly. 

@asyncio.coroutine 
def tick(): 
    while 1: 
     data = yield from queue.get() 
     print('Data received: {}'.format(data)) 

def main(): 
    loop = asyncio.get_event_loop() 
    loop.add_reader(sys.stdin, handle_stdin) 
    loop.run_until_complete(tick())  

if __name__ == '__main__': 
    main() 

有較少的邏輯參與比使用Event,你需要確保你設置/取消正確,並且不需要sleep,喚醒,檢查,回到睡眠,循環,就像使用全局變量一樣。因此,Queue方法更簡單,更小,並且阻止事件循環比其他可能的解決方案更少。其他解決方案在技術上是正確的,因爲它們將正常工作(只要您在if event.is_set()if data is not None:塊內不引入任何yield from調用)。他們只是有點笨重。

+0

非常感謝@dano,'queue'的方法看起來比事件''好得多。 –

2

如果你想等待一個事件,你應該使用Event.wait而不是輪詢is_set

@asyncio.coroutine 
def tick(): 
    while True: 
     yield from event.wait() 
     print('Data received: {}'.format(event.data)) 
     event.clear() 
+0

確實,事實上,即使是沒有循環的event.wait()產生的一個簡單的yield也應該是足夠的。 –