Python asyncio: reader 回调和协程通信
Python asyncio: reader callback and coroutine communication
我正在尝试实现将数据从标准输入传递到协程的简单想法:
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
的方法很好,那么使用变量也可以吗?
谢谢。
如果您想等待一个事件,您可能应该使用 Event.wait
而不是轮询 is_set
。
@asyncio.coroutine
def tick():
while True:
yield from event.wait()
print('Data received: {}'.format(event.data))
event.clear()
我认为asyncio.Queue
更适合这种producer/consumer关系:
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
相比,涉及的逻辑更少,您需要确保 set/unset 正确,并且不需要 sleep
,唤醒,检查,返回睡觉,循环,就像全局变量一样。因此 Queue
方法比其他可能的解决方案更简单、更小,并且阻塞事件循环的次数更少。其他解决方案在技术上是 正确的 ,因为它们将正常运行(只要您不在内部引入任何 yield from
调用 if if event.is_set()
和 if data is not None:
块)。它们只是有点笨重。
我正在尝试实现将数据从标准输入传递到协程的简单想法:
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
的方法很好,那么使用变量也可以吗?
谢谢。
如果您想等待一个事件,您可能应该使用 Event.wait
而不是轮询 is_set
。
@asyncio.coroutine
def tick():
while True:
yield from event.wait()
print('Data received: {}'.format(event.data))
event.clear()
我认为asyncio.Queue
更适合这种producer/consumer关系:
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
相比,涉及的逻辑更少,您需要确保 set/unset 正确,并且不需要 sleep
,唤醒,检查,返回睡觉,循环,就像全局变量一样。因此 Queue
方法比其他可能的解决方案更简单、更小,并且阻塞事件循环的次数更少。其他解决方案在技术上是 正确的 ,因为它们将正常运行(只要您不在内部引入任何 yield from
调用 if if event.is_set()
和 if data is not None:
块)。它们只是有点笨重。