的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
调用)。他们只是有点笨重。
答
如果你想等待一个事件,你应该使用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也应该是足够的。 –
非常感谢@dano,'queue'的方法看起来比事件''好得多。 –