How to Use Threads for IO Tasks in Python?

By | September 26, 2021
How to Use Threads for IO Tasks in Python

In Computing when a program is in execution is known as Process, further a Process is subdivided into multiple threads executions, which are also known as the LightWeight processes. To know more about the difference between Processes and Threads click here.

Python’s GIL

Python GIL stands for Global Interpreter Lock, which is a mutex (Mutual Exclusion Locking Mechanism) or lock which make sure that Python Interpreter executes only one thread at a time.

Vamware

The Python GIL is one of the main reasons why Python does not support multi-threading or multi-tasking, which prevents Python to take full advantage of multi-core and multiprocessor Computers.

The GIL is only in the C implementation of Python i.e. CPython, and other Implementations of Python like Jython, and IronPython do not have GIL.

Python Threading Module

If Python has GIL which does not support multi-threading, so how we achieve Multi-Threading in Python with Python threading Module?

The main task of GIL is not to prevent Python from multi-threading its main objective is executing only one thread at a time.

With the help of Python threading module we can perform multi-threading in Python. And when I say multithreading in Python it simply means executing two threads in the interpreter so fast, that it gives an illusion of two threads executing concurrently.

The threading module uses context switching when executing multiple threads, it switches from one thread to another if the thread taking time to execute. Even in multi-threading, only one thread executes at a time, because of context switching and speed of executing it looks like they are executing parallelly or concurrently.

Why use Multithreading in Python?

Multi-Threading may drastically increase the performance of the Python program. We should only use multi-threading in Python when the functions are independent of each other.

It is not guaranteed that the multi-threading will improve the program execution speed, in some cases, it might take more time than a single thread execution. So before using multi-threading in Python make sure that your program is suitable for multi-threading or not.

How to Archive Multi-Threading in Python

With the help of the Python threading module, we can achieve multithreading in Python or we can execute two threads concurrently.

Before using the threading module let’s see how much time a simple program takes to execute with Python default single threading, so we could distinguish the program with single-threading and the program with multi-threading.

Python Single Thread Program

import time

start_time = time.perf_counter()

def function1():
    for _ in range(3):
        print("Function 1")
        
        #sleep for 3 seconds
        time.sleep(3)

def function2():
    for _ in range(3):
        print("Function 2")

        #sleep for 3 seconds
        time.sleep(3)

function1()
function2()

finish_time = time.perf_counter()

#total execution time
total_time = round(finish_time-start_time,2)

print("The Complete Program took around", total_time , "seconds to execute")
Output
Function 1
Function 1
Function 1
Function 2
Function 2
Function 2
The Complete Program took around 18.14 seconds to execute

From the above output, you can see that the program took around 18 seconds to execute, which makes sense because we have put 3 seconds of sleep in both the functions for loop. And because of the synchronous behavior of execution, the Python program executed in 18 seconds.  So how can we make the above program faster the answer is Multi-threading.

Python Multi-Thread Program

In the above program, you can also see that the function1 is independent of function2 so here we can use multi-threading and, and when function1 is in sleep, with context switching the multi-threading will switch to function2 and execute function2, this will reduce the time of execution and make the program faster.

import time
from threading import *

start_time = time.perf_counter()

def function1():
    for _ in range(3):
        print("Function 1\n")
        
        #sleep for 3 seconds
        time.sleep(3)
def function2():
    for _ in range(3):
        print("Function 2\n")

        #sleep for 3 seconds
        time.sleep(3)

#create threads object
t1= Thread(target= function1)
t2= Thread(target= function2)

#start thread execution
t1.start()
t2.start()

#complete the above program code first
t1.join()
t2.join()

finish_time = time.perf_counter()

#total execution time
total_time = round(finish_time-start_time,2)

print("The Complete Program took around", total_time , "seconds to execute")

Output

Function 1
Function 2

Function 1
Function 2

Function 1
Function 2

The Complete Program took around 9.08 seconds to execute

From the above output you can see that, with the help of multi-threading in Python, we execute the same code in 9 seconds which took 18 seconds in the single thread.

When we try to use multi-threading in Python first we need to initialize the thread objects for our functions or sub-routines using Thread() module.

The start() method starts executing the thread, it is similar to calling a function.

The join()method make sure that the thread function finishes its execution first before executing the below code.

Conclusion

Multi-Threading with Python threading module does not execute two threads concurrently, it’s just an illusion. In the background the threading module switch between the Thread() object, so it looks like they are executing concurrently, but actually, they are executing one at a time.

The Python threading module come very useful and increase the performance of the python Program when the initialized threads are independent of each other and the program is not Input-Output bound. Else the multi-threading can also decrease the program performance and take more time than a single thread.

People are also reading: 

Leave a Reply

Your email address will not be published. Required fields are marked *