Sequential vs Asynchronous programming in Python

INTRODUCTION

This blog post aims to compare sequential and asynchronous programming in Python and demonstrate how to convert a sequential program to an asynchronous one.

SEQUENTIAL PROGRAMMING

Sequential programming is a traditional programming paradigm where the program instructions are executed sequentially, one after the other. This means that each instruction is executed in order, and the program moves on to the next instruction only after the current one has completed. Sequential programming is often used for simple applications that do not require complex logic or control flow, such as command-line utilities or small scripts. While sequential programming is straightforward and easy to understand, it can be slow and inefficient for more complex applications.

ASYNCHRONOUS PROGRAMMING

Asynchronous programming is a programming paradigm that allows tasks to be executed in a non-blocking way. This means that the program can continue to execute other tasks while waiting for a particular task to complete. Asynchronous programming is particularly useful for tasks that involve input/output operations or network operations, where the program would otherwise block and wait for the operation to complete before continuing. By using asynchronous programming, the program can continue to process other tasks while waiting for the input/output operation or network operation to complete, resulting in more efficient use of system resources and a faster overall program execution time.

SCENARIO

Let’s consider a real-world example to simplify the concept. We have a fictional character named Peter. Every morning, Peter wakes up, freshens up, and then starts his day with breakfast. To functionize his mornings’ routine, we can assume that Peter loves omelettes and coffee. It takes him 4 minutes to eat the omelette and another 3 minutes to drink his coffee. For simplicity in our Python code, we will consider each delay number in seconds.

After breakfast, Peter spends around 5 minutes scrolling through social media or checking his emails. Let’s see this scenario in Python code:

# Peter's morning
#wake-up; then, freshen-up
import time
 
def eat_breakfast():
    time.sleep(4)
    print("A delicious omelette")
 
def drink_coffee():
    time.sleep(3)
    print("Wow, it was a nice hot black coffee")
 
def scroll_instagram():
    time.sleep(5)
    print("You're all caught up")
 
# time.perf_counter() returns the value of a performance counter    
start = time.perf_counter()
eat_breakfast()
drink_coffee()
scroll_instagram()
end = time.perf_counter()
print("it's done in:",int(end - start),"seconds")

After running the code above, each function executes line-by-line and the entire program completes in 12 seconds, which is expected. However, Peter may want to use the waiting time for his coffee to cool down to check a notification on his phone. In other words, he wants to use the waiting times of each function to run another function.

Another tangible and practical example of this is calling an API while uploading something to a server. In this case, functions must be written and run asynchronously.

Let’s modify Peter’s routine. The first approach is to perform the tasks sequentially but in an asynchronous fashion.

# Peter's morning
# wake-up; then, freshen-up
import time
import asyncio
 
async def breakfast():
    print("half of omelette")
    await scrolling()
    print ("Coffee & omelette are served")
    await asyncio.sleep(3)
 
async def scrolling():
    print("check some notifications")
    await asyncio.sleep(3)
    print("a sip of coffee")
    await asyncio.sleep(2)
    print("You're all caught up")
 
# time.perf_counter() returns the value of a performance counter    
start = time.perf_counter()
# functions run via the below command in asynchronous programming
# execute only one fuction because the other one is calling inside the first one
asyncio.run(breakfast())
end = time.perf_counter()
print("it's done in:",int(end - start),"seconds")

In the above program, Peter uses his waiting time to do something else. We have changed the functions to an asynchronous style; however, upon closer inspection, it still executes sequentially. We are calling one function inside another function, and it’s something doable in sequential as well.

The second approach (pure async), which is async coding, is to create a task inside your async function and instruct your function to take care of the task during the waiting time. The following snippet is the modified version of our code.

import time
import asyncio
 
async def breakfast():
    task = asyncio.create_task(scrolling())
    print("half of omelette")
    await asyncio.sleep(3)
    print ("Coffee & omelette are served")
    await task
 
async def scrolling():
    print("check some notifications")
    await asyncio.sleep(3)
    print("a sip of coffee")
    await asyncio.sleep(3)
    print("You're all caught up")
 
start = time.perf_counter()
asyncio.run(breakfast())
end = time.perf_counter()
print("it's done in:",int(end - start),"seconds")

It could be said that, the second code is more efficient and faster than the first one because it uses asynchronous programming. It allows the program to do other things while waiting for a task to complete, instead of blocking the execution.

IN A NUTSHELL

Sequential programming executes a set of instructions in the order in which they are written. This means that each instruction must be completed before the next one can begin. In contrast, asynchronous programming allows multiple instructions to be executed at the same time, without having to wait for each one to finish before starting the next.

One advantage of sequential programming is that it tends to be easier to understand and debug. However, it can be slower when dealing with complex tasks or large datasets. Asynchronous programming can be much faster, but it can also be more difficult to implement and debug.

Both programming approaches have their pros and cons, and the choice between them depends on the specific needs of the project. In general, sequential programming may be better suited for simpler tasks, while asynchronous programming may be more appropriate for more complex and time-consuming tasks.

Post by Amin Sedighfar

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments