Python asyncio: reader and coroutine feedback

I am trying to implement the simple idea of ​​passing 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() 

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

 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 

My questions are: is the approach with Event correct? Or is there a better way with other asyncio objects to solve this problem? Then, if the approach with Event is good, is using a variable also good?

Thanks.

+10
python coroutine python-asyncio
source share
2 answers

I think asyncio.Queue much better suited for this kind of relationship between producer and 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() 

There is less logic involved than with Event , which needs to be checked to see if you installed / reset correctly, and there is no need for sleep , waking up, checking, returning to sleep mode, or a loop, as with a global variable. Thus, the Queue approach is simpler, smaller, and blocks the event loop less than other possible solutions. Other solutions are technically correct in that if event.is_set() , that they will function properly (until you if event.is_set() any yield from calls inside if if event.is_set() and if data is not None: blocks). They are just a little awkward.

+14
source share

If you want to wait for an event, you should probably use Event.wait instead of polling is_set .

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

All Articles