【问题标题】:Python asyncio: reader callback and coroutine communicationPython asyncio:阅读器回调和协程通信
【发布时间】:2015-06-11 01:42:24
【问题描述】:

我正在尝试实现一个将数据从标准输入传递到协程的简单想法:

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

谢谢。

【问题讨论】:

    标签: python python-3.x python-3.4 coroutine python-asyncio


    【解决方案1】:

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

    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 方法比其他可能的解决方案更简单、更小,并且阻塞事件循环的次数更少。其他解决方案在技术上是正确,因为它们可以正常运行(只要在 if event.is_set()if data is not None: 块内不引入任何 yield from 调用)。它们只是有点笨重。

    【讨论】:

    • 非常感谢@dano,queue 方法看起来确实比"event" 更好。
    【解决方案2】:

    如果您想等待某个事件,您可能应该使用Event.wait 而不是轮询is_set

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

    【讨论】:

    • 没错,事实上,即使是一个没有循环的简单yield from event.wait() 也应该足够了。
    猜你喜欢
    • 2020-12-29
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 2020-10-16
    • 2018-02-25
    • 2019-03-16
    • 1970-01-01
    • 2015-09-20
    相关资源
    最近更新 更多