In this blog, we’ll delve into Multithreading in Python, unlocking the power of concurrent programming to enhance your application’s performance.
Multithreading is a technique that allows an application to execute multiple tasks concurrently. Speed is often a critical factor for applications, and achieving optimal performance relies heavily on time efficiency. Multithreading is a fundamental approach used across various programming languages, including Python, to enhance the efficiency of applications by enabling them to perform multiple tasks simultaneously.
What is Multitasking?
In simple terms, multitasking refers to the ability to carry out multiple tasks simultaneously or in parallel. From a technical perspective, it involves an operating system’s capacity to manage and execute various tasks at the same time. For instance, while we listen to music, download files, and browse the internet all at once, the operating system handles these tasks concurrently. Multitasking is a valuable feature designed to enhance efficiency, save time, and boost overall productivity.
In the realm of operating systems, we commonly encounter two types of multitasking:
- Thread-based
- Process-based
In this tutorial, we will delve into the concept of thread-based multitasking.
What is Thread?
A thread is a sequential path of control within a process. It’s worth noting that a single process can involve multiple threads, and each thread is responsible for executing a specific task. For instance, consider playing a cricket video game on your PC. Although the game is treated as a single process, it simultaneously runs various threads. These threads handle distinct functions, such as collecting user input, providing commentary audio, and controlling player movements during the game. All these threads operate harmoniously within the same process, collectively contributing to the overall application’s performance.
Typically, every process has a primary thread, commonly referred to as the “main thread.” The main thread is positioned on a stack, ensuring its continuous operation. Additionally, it is responsible for creating subordinate thread objects, initiating these sub-threads in the process.
When should multithreading be employed in Python?
Multithreading is a valuable and significant technique for enhancing application performance, particularly when time efficiency is a priority. However, it’s not applicable in all situations, as its usage depends on thread dependencies.
In the earlier EA game example, the commentary and player movement threads are considered independent threads. They operate autonomously, not relying on other threads for their functionality.
How do I implement Multithreading in Python?
Multithreading in Python by utilizing the “threading” module, which needs to be imported. Before making use of this module, you may also need to set up an Anaconda environment by executing the installation command provided.
conda install –c conda-forge tbb
Once the Anaconda environment is successfully installed, you should import the required modules into your program to enable the implementation of multithreading.
import threading
from threading import *
How to create Threads in Python:
Creating Threads in Python: Different Approaches for Thread Creation
In Python, threads can be created using various methods, including:
- Creating threads without defining a class.
- Inheriting the Thread class to create threads.
- Creating threads without inheriting the Thread class.
Creating threads without defining a class:
In Python, it is possible to create threads without the necessity of defining a class.
Example:
from threading import *
print(current_thread().getName())
def main_t():
print(“Child Thread”)
child_t=Thread(target=main_t)
child_t.start()
print(“Name of the Executing thread :”,current_thread().getName())
Output:
MainThread
Child Thread
Name of the Implementing thread: MainThread
In this example, we use the concept of threads without defining a separate class. The initial thread that starts running is called the main thread. This main thread is responsible for creating a sub-thread when it accesses a method called main_t(). Additionally, the main thread is responsible for running the last thread as well.
Inheriting Thread class
This approach involves the subclass inheriting properties from the superclass, known as the “thread class.” The subclass has the capability to create multiple sub-threads to accomplish various tasks. However, it’s important to note that the subclass is limited to overriding only the “init()” and “run()” methods to manage thread execution. Other life cycle methods cannot be overridden.
Following is the Multithreading Example in Python:
Example
import threading
class my_thread(threading.Thread):
def run(self):
for x in range(5):
print(“child thread”,x)
a = my_thread()
a.start()
Output:
child thread 0
child thread 1
child thread 2
child thread 3
child thread 4
In this example, we employ threading by inheriting the “Thread” class. We achieve this by utilizing the “threading.Thread” class. We also utilize the “run” method to execute sub-threads. It is essential to override the “run()” method to ensure that the thread’s lifecycle is initiated by calling “start().”
Example without inheriting Thread class:
from threading import *
class ex:
def my_func(self):
for x in range(5):
print(“Sub Thread”,x)
obj=ex()
t1=Thread(target=obj.my_func)
t1.start()
t1.join()
print(“done”)
Output:
Sub Thread 0
Sub Thread 1
Sub Thread 2
Sub Thread 3
Sub Thread 4
Done
In this example, we create threads without the need to inherit the “Thread” class. We accomplish this by defining a class containing a method named “my_func.” We initiate and run the sub-threads while also invoking the main thread in the final statement.
Benefits of Thread:
- Enhanced the application’s speed by making responses faster.
- Reduced the amount of code.
- Made more efficient use of computer resources.
- Enabled tasks to happen at the same time and one after another
In the examples below, we’ll see how processes work with and without using multithreading in Python to help illustrate these points.
For Instance:
import time
def square_func(n):
for i in n:
time.sleep(1)
def cube_func(n):
for i in n:
time.sleep(1)
n=[1,2,3,4,5,6,7,8]
start=time.time()
square_func(n)
cube_func(n)
end=time.time()
print(end-start)
Output:
16.000915050506592
In this example, we do not utilize any threading techniques for execution. In this program, it takes approximately 16 seconds to complete one round of processing.
Let’s use the same example with the Multithreading concept:
Example:
from threading import *
import time
def square_func(n):
for i in n:
time.sleep(1)
#print(‘i%2 = ‘,i%2)
def cube_func(n):
for x in n:
time.sleep(1)
#print(‘i%3 = ‘,i%3)
n=[1,2,3,4,5,6,7,8]
start=time.time()
th1=Thread(target=square,args=(n,))
th2=Thread(target=cube,args=(n,))
th1.start()
time.sleep(1)
th2.start()
th1.join()
th2.join()
end=time.time()
print(end-start)
Output:
9.001514911651611
In this example, we’ve managed to cut down the response time from the previous instance to just 9 seconds per round. This shows the advantage of using multithreading into programs.
Conclusion:
In conclusion, Multithreading in Python offers several benefits, including improved performance, reduced execution time, more efficient resource utilization, and the ability to run tasks in parallel. By leveraging multithreading, Python programs can handle concurrent tasks more effectively, making them faster and more responsive. However, it’s important to design multithreaded programs carefully to avoid potential issues such as race conditions and deadlocks. When used appropriately, multithreading can significantly enhance the efficiency and responsiveness of Python applications.
Ready to dive into the world of multithreading in Python? Join our
Python Training in Chennai and unlock the power of concurrent programming!