的Python ASYNCIO:读者回调和协程通信

问题描述:

我想实现从标准输入传递数据给协程的一个简单的想法:的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的方法是好的,使用变量是否也很好?

谢谢。

我觉得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'的方法看起来比事件''好得多。 –

如果你想等待一个事件,你应该使用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也应该是足够的。 –