Study the code below, chapter 18 from Fluent Python by Luciano Ramalho is an excellent resource on the asyncio module. Also, never forget the docs itself at https://docs.python.org/3/library/asyncio.html
#!/usr/bin/env python3
# spinner_asyncio.py
# credits: Example by Luciano Ramalho inspired by
# Michele Simionato's multiprocessing example in the python-list:
# https://mail.python.org/pipermail/python-list/2009-February/538048.html
import asyncio
import itertools
import sys
@asyncio.coroutine # <1>
def spin(msg):
write, flush = sys.stdout.write, sys.stdout.flush
for char in itertools.cycle('|/-\\'):
status = char + ' ' + msg
write(status)
flush()
write('\x08' * len(status))
try:
yield from asyncio.sleep(.1) # <3>
except asyncio.CancelledError: # <4>
break
write(' ' * len(status) + '\x08' * len(status))
@asyncio.coroutine
def slow_function(): # <5>
# pretend waiting a long time for I/O, Non-blocking call!
yield from asyncio.sleep(3) # <6>
return 42
@asyncio.coroutine
def supervisor(): # <7>
spinner = asyncio.async(spin('thinking!')) # <8>
print('spinner object:', spinner) # <9>
result = yield from slow_function() # <10>
spinner.cancel() # <11>
return result
def main():
loop = asyncio.get_event_loop() # <12>
result = loop.run_until_complete(supervisor()) # <13>
loop.close()
print('Answer:', result)
if __name__ == '__main__':
main()
1: Coroutines intended for use with asyncio should be decorated with @asyn
cio.coroutine. This not mandatory, but is highly advisable.
3: Use yield from asyncio.sleep(.1) instead of just time.sleep(.1), to sleep
without blocking the event loop.
4: If asyncio.CancelledError is raised after spin wakes up, it’s because
cancellation was requested, so exit the loop.
5: slow_function is a coroutine, and uses yield from to let the event loop
proceed while this coroutine pretends to do I/O by sleeping.
6: The yield from asyncio.sleep(3) expression handles the control flow to the
main loop, which will resume this coroutine after the sleep delay.
7: supervisor is a coroutine as well, so it can drive slow_function with yield
from.
8: asyncio.async(…) schedules the spin coroutine to run, wrapping it in a Task
object, which is returned immediately
9: Display the Task object. The output looks like Task pending coro= spin()
running at spinner_asyncio.py:12.
10: Drive the slow_function(). When that is done, get the returned value.
Meanwhile, the event loop will continue running because slow_function
ultimately uses yield from asyncio.sleep(3) to hand control back to the main
loop.
11: A Task object can be cancelled; this raises asyncio.CancelledError at the yield
line where the coroutine is currently suspended. The coroutine may catch the
exception and delay or even refuse to cancel.
12: Get a reference to the event loop.
13: Drive the supervisor coroutine to completion; the return value of the coroutine
is the return value of this call.