Python异步:阅读器回调和协程通信 [英] Python asyncio: reader callback and coroutine communication

查看:186
本文介绍了Python异步:阅读器回调和协程通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现将数据从stdin传递到协程的简单想法:

I am trying to implement a simple idea of passing a data from stdin to a coroutine:

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()

此代码可以正常工作,但是它的简化版本带有变量inste Event 对象的广告也可以工作:

This code works fine, however a simplified version of it with a variable instead of an Event object works too:

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 的方法很好,那么使用变量也可以吗?

My questions are: is the approach with Event correct? Or is there a better way with another asyncio objects to handle this kind of problem? Then, if the approach with Event is fine, is using a variable is fine as well?

谢谢。

推荐答案

我认为 asyncio.Queue 更适合于这种生产者/消费者关系:

I think asyncio.Queue is much better suited for this kind of producer/consumer relationship:

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()

Event 相比,涉及的逻辑更少,您需要确保正确设置/取消设置,并且不需要 sleep ,唤醒,检查,回到睡眠,循环,就像使用全局变量一样。因此,与其他可能的解决方案相比, Queue 方法更简单,更小,并且对事件循环的阻塞更少。其他解决方案从技术上讲是正确,因为它们可以正常运行(只要您在调用中不引入 yield的情况下 c $ c> if event.is_set() if data not None:块)。他们只是笨拙。

There's less logic involved than with an Event, which you need to make sure you set/unset properly, and there's no need for a sleep, wakeup, check, go back to sleep, loop, like with the global variable. So the the Queue approach is simpler, smaller, and blocks the event loop less than your other possible solutions. The other solutions are technically correct, in that they will function properly (as long as you don't introduce any yield from calls inside if if event.is_set() and if data is not None: blocks). They're just a bit clunky.

这篇关于Python异步:阅读器回调和协程通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆