Create an event loop (which automatically becomes the default event loop in the context).
In [1]:
import asyncio
loop = asyncio.get_event_loop()
Run a simple callback as soon as possible:
In [2]:
def hello_world():
print('Hello World!')
loop.stop()
loop.call_soon(hello_world)
loop.run_forever()
Coroutines can be directly scheduled in the eventloop.
In [3]:
async def aprint(text):
await asyncio.sleep(1)
print(text)
return 42
loop.run_until_complete(aprint('Hello world!'))
Out[3]:
You can use as many awaits as you like in a couroutine:
In [4]:
async def aprint_twice(text):
await asyncio.sleep(1)
print(text)
await asyncio.sleep(1)
print(text + ' (once more)')
return 42
loop.run_until_complete(aprint_twice('Hello world!'))
Out[4]:
Multiple Coroutines can be combined and executed concurrently:
In [5]:
loop.run_until_complete(asyncio.gather(aprint('Task 1'), aprint('Task 2')))
Out[5]:
Exceptions work just like you would expect
In [6]:
async def raiser():
await asyncio.sleep(1)
raise ValueError()
async def catcher():
try:
await raiser()
except ValueError:
print('caught something')
loop.run_until_complete(catcher())
Not awaiting a coroutine raises an error.
In [7]:
a = aprint('Did I forget something?')
del(a)
Awaiting something that is not awaitable raises an error.
In [8]:
async def fail():
await aprint
loop.run_until_complete(fail())
In [9]:
class AsyncContextManager:
async def __aenter__(self):
await aprint('entering context')
async def __aexit__(self, exc_type, exc, tb):
await aprint('exiting context')
async def use_async_context():
async with AsyncContextManager():
print('Hello World!')
loop.run_until_complete(use_async_context())
One example is using locks (even though this doesn't require async exiting).
In [10]:
lock = asyncio.Lock()
async def use_lock():
async with lock:
await asyncio.sleep(1)
print('much lock, such concurrency')
loop.run_until_complete(asyncio.gather(use_lock(), use_lock()))
Out[10]:
Prepare a simple MongoDB collection to show this feature.
In [11]:
from motor.motor_asyncio import AsyncIOMotorClient
collection = AsyncIOMotorClient().aiotest.test
loop.run_until_complete(collection.insert({'value': i} for i in range(10)))
Out[11]:
The async for-loop saves us the boilerplate code to await each next value. Note that it runs sequentially (i.e., the elements are fetched after each other).
In [12]:
async def f():
async for doc in collection.find():
print(doc)
loop.run_until_complete(f())
In [13]:
loop.run_until_complete(collection.drop())
Futures are awaitable as well.
In [14]:
import collections
isinstance(asyncio.Future(), collections.abc.Awaitable)
Out[14]:
Generators exceptions do not confuse Coroutines.
In [15]:
async def unconfused():
g = iter(range(1))
next(g)
next(g)
await asyncio.sleep(1)
print('done!')
loop.run_until_complete(unconfused())
Async generators on the other hand could be confused if the optinal decorator is not used.
In [16]:
# @asyncio.coroutine
def confused():
g = iter(range(1))
next(g)
next(g)
yield from asyncio.sleep(1)
print('done!')
loop.run_until_complete(confused())