Multithreading in Python is a way of achieving multitasking in python using the concept of threads.
What is a Thread?
A thread is a component of any process managed by the operating system. The OS achieves parallelism or multitasking by dividing the process among threads. It is a lightweight process that ensures a separate flow of execution.
What are the Benefits of Multithreading in Python?
There are quite a few benefits to creating multithreaded applications. Let’s look at some of the benefits here:
- Effective utilization of resources
- More responsive
- Resource sharing makes it more economical
- Effective use of Multiprocessor architecture due to parallelism
- Saves time
- Threads (since part of the same process) communicate with each other more easily than if they were separate processes
- They do not require much memory overhead
- Multi-threaded servers and interactive GUIs use multithreading exclusively.
How to Achieve Multithreading in Python?
Let’s move on to creating our first multi-threaded application.
1. Import the threading module
For the creation of a thread, we will use the
threading module consists of a
Thread class which is instantiated for the creation of a thread.
A thread can be created by the creation of an object of the Thread class. The arguments for this class are as follows:
- target: The function to be invoked by the thread is specified here. This function is a callable object invoked by the
run()method of the thread.
- args: Here, we specify the arguments of the
def print_hi(num): print("Hi, you are customer ",num) t1 = threading.Thread(target=print_square, args=(10,))
The above code snippet invokes the
print_hi() function invoked as
target parameter. This function has one parameter namely
num which is specified using the
2. Starting the Thread
The thread is started by calling the
start() method of the
threading module on the Thread object. The illustration of the same is shown below:
It must be called at most once per thread object. It arranges for the object’s
run() method to be invoked in a separate thread of control.
This method will raise a
RuntimeError if called more than once on the same thread object.
The thread is invoked within a program which is a process by itself. So, during the execution of the thread, the main program continues its execution as well.
Hence, we can pause the activity of the main program (run by the main thread) until the completion of the created thread. The illustration of the same is as follows.
3. Join method of Thread
def print_hi(num): print("Hi, you are customer ",num) t1 = threading.Thread(target = print_hi, args=(10,)) t1.start() t1.join() print("End")
In the snippet above, the
Thread class is used to create an object and it has been named as t1. The
start() method is invoked on the thread object t1 which marks the beginning of the thread activity.
join() method is then called. By doing so, we ensure that the main program halts execution of the main thread and waits until the completion of thread t1. Once t1 has completed its activity, the main thread (main program) can continue its execution. Hence, the line
print("End") is executed only after the completion of the thread activity.
Hi, you are customer 10 End
Without the use of the
join() method, the interpreter has the choice between the two print statements –
print("Hi, you are customer ", num), and
print("End"). In such scenarios, it cannot be predicted which print statement will be displayed first because the execution of these lines is chosen by the interpreter.
4. Synchronizing Threads in Python
Thread synchronization is defined as a mechanism to ensure that no two threads execute a particular program segment that accesses shared resources. Such sections of the program are referred to as critical sections.
It is necessary to ensure that two threads do not access this resource simultaneously as this can lead to a race condition.
A race condition is defined as a scenario when two or more threads access the shared resources with write permission and try to change the data. Thus, the value of such variables becomes unpredictable.
Hence, we use locks in the program that temporarily halt the execution of a program until the lock is released. This is done to ensure that two threads do not access the same variable and cause conflicts.
Disadvantages of Multi-threading
- Increases the complexity of the program.
- Synchronization of shared resources (objects, data) is necessary.
- Difficult to debug unpredictable results
- Constructing and synchronizing threads is CPU/memory intensive.