In previous post, we saw that Python uses OS event notification system to make non blocking calls and achieve concurrency in case of I/O bound tasks. How it keeps track of these tasks, is handled by Event Loop. Let’s dig deeper into this concept.
To keep track of tasks(a block of code/function) which are waiting for I/O we use event loop. For better understanding, first let’s understand terminologies involved with this concept.
Coroutine
It is similar to a Python function syntax, difference is it is prefixed by async keyword. Coroutines are functions which can pause in between and later can be resumed. When coroutine encounter any I/O task, it gets paused and we can run other coroutines in meanwhile thus giving us concurrency.
Tasks:
These are wrapper around coroutine to handle additional metadata of each coroutine.
Let’s start with eventloop now.
Eventloop is nothing but a continously loop which keep executing tasks. Taking a sudo code for the same.
def make_request():
cpu_operation1()
io_operation()
cpu_operation2()
task1 = make_request()
task2 = make_request()
tasks = [task1, task2]
while True:
for task in tasks:
execute task
We have created 2 tasks that are added to event loop queue. How this will executed?
At any point of time only 1 cpu task is running and while one is waiting for I/O, other one is executing, that’s how concurrency comes into play.
Eventloop, tasks and coroutines are the fundamental concepts on which asyncio library of Python works. From python program to coroutine, this is how these are related.
Think of it like a restaurant:
Python Program = The Restaurant
Event Loop = The Manager
Tasks = The Orders
Coroutines = The Recipes
In next blog we will understand how asyncio uses these construct for leveraging concurrency using single thread.
Conclusion:
Smaller constructs like event loop, coroutines, tasks are all part of underlying mechanism of asyncio library that achieves concurrency with minimum overload which comes with threading as it use single thread.