When to use the @asyncio.coroutine decorator
If you have a function that should use yield from to call a coroutine, you should decorate it with asyncio.coroutine . Also note that coroutines are often (not always) viral. As soon as you add the yield from function to the function, it will become a coroutine, and in addition, any function that calls this coroutine usually (though not always) must also have a coroutine.
When to use asyncio.async
Why coroutines are not always viral? Because you do not always need to use yield from to call a coroutine. You need to use yield from if you want to call coroutine coroutine and wait for it to complete. If you just want to run the coroutine in the background, you can simply do this:
asyncio.async(coroutine())
This will start coroutine to start as soon as the control returns to the event loop; he will not wait for the coroutine to finish until the next line. A regular function can use this to schedule the execution of a coroutine, without also requiring it to become a coroutine itself.
You can also use this approach to run multiple coroutines at the same time. So, imagine that you have these two coroutines:
@asyncio.coroutine def coro1(): yield from asyncio.sleep(1) print("coro1") @asyncio.coroutine def coro2(): yield from asyncio.sleep(2) print("coro2")
If you have this:
@asyncio.coroutine def main(): yield from coro1() yield from coro2() yield from asyncio.sleep(5) asyncio.get_event_loop().run_until_complete(main())
After 1 second, "coro1" will be printed. Then, after two seconds (so only three seconds), "coro2" will be printed, and after five seconds the program will exit, executing 8 seconds of the total execution time. Alternatively, if you used asyncio.async :
@asyncio.coroutine def main(): asyncio.async(coro1()) asyncio.async(coro2()) yield from asyncio.sleep(5) asyncio.get_event_loop().run_until_complete(main())
This will print "coro1" after one second, "coro2" after one second, and the program will exit after 3 seconds, for a total of 5 seconds of execution time.
How does this affect your code?
So, following these rules, your code should look like this:
import asyncio class ChatBot: def __init__(self, reader, writer):
Another thing to keep in mind is that adding yield from in front of a function does not magically make this call non-blocking. Does not add the @asyncio.coroutine decorator. Functions are only non-blocking if they directly or indirectly call their own asyncio coroutines that use non-blocking I / O and integrate with the asyncio event asyncio . For example, you mentioned REST API calls. To prevent these REST API calls from blocking the event loop, you need to use the aiohttp library or asyncio.open_connection . Using something like requests or urllib blocks the loop because they are not integrated with `asyncio.