Python异步IO:读取器回调和协同程序通信

Python异步IO:读取器回调和协同程序通信,python,python-3.x,python-3.4,coroutine,python-asyncio,Python,Python 3.x,Python 3.4,Coroutine,Python Asyncio,我试图实现一个简单的想法,将数据从stdin传递到协同程序: 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():

我试图实现一个简单的想法,将数据从stdin传递到协同程序:

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()
此代码工作正常,但简化版本的代码使用变量而不是
事件
对象也可以工作:

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对象来处理此类问题? 那么,如果使用
事件
的方法很好,那么使用变量也很好吗


多谢各位

如果要等待事件,可能应该使用而不是轮询
is\u set

@asyncio.coroutine
def tick():
    while True:
        yield from event.wait()
        print('Data received: {}'.format(event.data))
        event.clear()
我认为更适合这种生产者/消费者关系:

import asyncio
import sys

queue = asyncio.Queue()

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

async def tick():
    while 1:
        data = await 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()

事件
相比,所涉及的逻辑更少,您需要确保正确设置/取消设置该事件,并且不需要
睡眠
、唤醒、检查、返回睡眠、循环,就像使用全局变量一样。因此,
队列
方法比其他可能的解决方案更简单、更小,并且更少地阻塞事件循环。其他解决方案在技术上是正确的,因为它们可以正常工作(只要在if
if event.is_set()
if data not None:
块中不引入任何来自调用的
收益)。它们只是有点笨重。

没错,事实上,即使是一个简单的
从event.wait()
没有循环的屈服也应该足够了。非常感谢@dano,
queue
方法看起来确实比
“event”
方法好。