Questions
1a. What is Event Loop and how is created?
- Main and central mechanism of asyncio package. It is responsible for managing coroutines execution and handling event in asynchronous application.
- Event loop allows to halt and start again coroutines. Because of this many tasks can be executed simultaneously.
- Commonly Event loop is created as below when it creates Event loop and trigger coroutine.
asyncio.run(coroutine_function())
- More complex way:
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine_function())
1b. How to define asynchronous function in Python?
async def fetch_data():
data = await some_network_request()
return data
How to trigger async function?
# from other coroutine function:
async def main():
result = await coroutine_funct()
print(result)
# from synchronous context:
asyncio.run(coroutine_funct())
2a. What is basic task for await keyword in asyncio?
- It halts execution of current coroutine and allows other Event loop tasks to be executed. Because of this all program is not blocked.
- await also waits for finishing execution of awaitable object (other async function)
- await works only in async context in function defined by async. When used in synchronous context then SyntaxError is raised.
2b. What happen if you forget to use await keyword when calling async function
- Coroutine object will be created but not executed.
import asyncio
async def fetch_data():
print("Fetching data...")
await asyncio.sleep(2)
print("Data fetched!")
async def main():
fetch_data() # Brak await
print("This will print immediately")
asyncio.run(main())
fetch_data() returns coroutine object, but will not be executed
Also, RuntimeWarning will be triggered (starting from Python 3.8)
RuntimeWarning: coroutine 'fetch_data' was never awaited
3a. How to create and start task in asyncio
- Task it is object of class: '_asyncio.Task' created by asyncio.create_task(). It manages coroutine execution.
- When task is created then automatically coroutine is started in background.
async def my_coroutine():
print("Start")
await asyncio.sleep(1)
print("End")
async def main():
task = asyncio.create_task(my_coroutine())
print("Task created")
await task
asyncio.run(main())
Differences between task and coroutine
| Feature |
Coroutine |
Task |
| Trigerring |
Not automatically |
Coroutine is triggered immediately in background. |
| Parallelism |
Executes in the context of the current await / Event loop |
It is tool allowing coroutine to be executed parallel. |
| State |
Lack of self-monitoring capabilities |
Task has self-monitoring features. |
2b. What is difference beetwen asyncio.run and loop.run_until_complete?
asyncio.run()
- Create new Event loop.
- Executes the given coroutine.
- When coroutine is finished it closes Event loop and clean resources.
- Event loop is automatically managed.
- Easy to use, but can be used only only once in the program.
loop.run_until_complete()
3a. How to create and run more tasks in parallel?
- asyncio.gather()
- asyncio.create_task() => should be run in some loop because only 1 task can be created by call
3b. What is difference between 'asyncio.gather()' and 'asyncio.create_task()'?
import asyncio
async def task1():
await asyncio.sleep(1)
print("Task 1 done")
async def task2():
await asyncio.sleep(2)
print("Task 2 done")
async def task3():
await asyncio.sleep(3)
print("Task 3 done")
async def main():
# Uruchamiamy wszystkie zadania jednocześnie i czekamy na ich zakończenie
await asyncio.gather(task1(), task2(), task3())
# Uruchomienie event loop
asyncio.run(main())
- await asyncio.gather() - multiple task run in one call
- asyncio.create_task() => it creates spacial objects (Tasks) that start coroutine immediately. It should be run in some loop because only 1 task can be created by call