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]:
All normal control structures can be used:
In [5]:
async def aprint_twice():
for i in range(1, 7):
await asyncio.sleep(0.5)
if i % 2:
print('even')
else:
print('uneven, waiting some more...')
await asyncio.sleep(1)
loop.run_until_complete(aprint_twice())
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())
Multiple Coroutines can be combined and executed concurrently:
In [7]:
tasks = asyncio.gather(aprint('Task 1'), aprint('Task 2'))
loop.run_until_complete(tasks)
Out[7]:
Note that this only took one second, not two!
In [8]:
async def remember_me():
print('I started.')
await aprint('Did I forget something?')
a = remember_me()
Note that nothing happens as long as the coroutine is not awaited. Even the synchronous print is not executed.
In [9]:
a = 42
Not awaiting a coroutine raises an error.
Awaiting a coroutine "later" is ok though.
In [10]:
a = aprint('Did I forget something?')
loop.run_until_complete(a)
del(a)
Awaiting something that is not awaitable raises an error.
In [11]:
async def fail():
await aprint
loop.run_until_complete(fail())
Prepare a simple MongoDB collection to show this feature.
In [12]:
from motor.motor_asyncio import AsyncIOMotorClient
collection = AsyncIOMotorClient().aiotest.test
loop.run_until_complete(collection.insert({'value': i} for i in range(10)))
Out[12]:
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 [13]:
async def f():
async for doc in collection.find():
print(doc)
loop.run_until_complete(f())
In [14]:
loop.run_until_complete(collection.drop())
In [15]:
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 [16]:
lock = asyncio.Lock()
async def use_lock():
async with lock:
await asyncio.sleep(1)
print('one after the other...')
tasks = asyncio.gather(use_lock(), use_lock())
loop.run_until_complete(tasks)
Out[16]:
Note that this took two seconds instead of one.