2015-04-06 5 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 проще, меньше и блокирует цикл событий меньше, чем другие возможные решения. Другие решения являются технически правильными, поскольку они будут функционировать должным образом (если вы не вводите никаких вызовов yield from внутри, если if event.is_set() и if data is not None: блоков). Они просто немного неуклюжи.

+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

Правда, на самом деле даже простой 'yield from event.wait()' без цикла должен быть достаточным. –

 Смежные вопросы

  • Нет связанных вопросов^_^