Before getting into the ‘How to’ part of our article, I wanted you to understand the difference between concurrency and parallelism. You might think, ‘Dude, why are you talking about that now?’. But to write a smart pythonic asynchronous code, you should understand the importance of their difference. Cool?
I recommend you to use the Right brain and it’s creative engine. Consider a guy who has two stones (of different weight) in his hands. Now he throws the two stones upward at the same time. Depending upon the weight, the two stones will come back to him at random time intervals. This is called parallelism. Now the same guy first throws one stone upward and rather than waiting for it to come back, he throws the other stone above. This is called concurrency.
In our above story, the stones sent upward are the requests, and when it comes back it is called response. In parallelism, we sent two requests at the same time using two hands (two threads or processes). But whereas in concurrency, we used a single hand (one thread or process) to make two requests.
Usually Python will wait for the response to reach back and then proceeds with sending the next one. This is called Blocking operation. When we do concurrency tasks, we are making the Python code do Non-blocking operation.
Okay. End of the story. Now let’s jump to the technical part.
So, let’s take the smart move. Here, we are not going to talk about the history and how things developed into the current module and so on. We are going to learn how to use the current features Python holds. Python introduced a new module in 3.4 called asyncio which made ‘writing asynchronous’ code much more easier.
Let’s see how to code.
There are few terminologies involved in Python’s asynchronous coding. First and foremost is Event Loop. This is the center of execution. This runs in the thread and executes the tasks in the queue. You can understand when you see the following code snippet.
import asyncio async def say(something, delay): await asyncio.sleep(delay) print(something) loop = asyncio.get_event_loop() task1 = loop.create_task(say('hi', 1)) task2 = loop.create_task(say('hoi', 2)) loop.run_until_complete(asyncio.gather(task1, task2))
If you see very clearly, the asyncio made the non-blocking operation look very much like a sequential code.
Line 1 - this imports the Python to our favorite module
Line 2 to 4 - this function is our async function that prints something with a delay
Line 6 - Initializes the event loop
Line 7,8 - Creates the task to be executed by our event loop
Line 9 - Mission Started
You might think, does it really work? What’s the difference between the above code and normal code. Because, when someone explained to me about this magical thing, I thought the same. I know how to help you out with that. Okay just see the two codes below.
When you see the sequential code, it first executes say(‘hi’, 1) by printing hi and sleeps for 1 second. And then it executes say(‘hoi’, 2) by printing hoi and sleeps for 2 second. So totally the time taken for the program to execute would be ~3seconds. But whereas, in our asynchronous program, when task1 is executed, it will sleep for 1 second, and at the same time task2 will also be executed. This makes the program complete in ~2seconds.
This small program won’t make a big difference. But while making http requests, we don’t need to wait till we receive the response. Now with asyncio, we can just do another request at the same time. Cool isn’t it? There are tons of applications because of async programming.
In our future article, I will get into the details of coroutines and how asyncio was built.
P.S. For beginners, use Python greater than 3.4 to run the above code snippets.