Multi-Threading in Python
In this post, we form an understanding of multithreading and understand its implementation in Python.

- Mutlithreading is a way of achieving multitasking
We use threads to achieve the ability to multitask in a computer, it requires us to have a general understanding of what threads are. And before understanding what a thread is, we need to know process.
- Process is an instance of a computer program that’s being executed.
Each process has an executable program, associated data, execution context(state of process). Thread is the smallest entity within a process that can scheduled for execution. It’s a set of instructions that can be run independently of other code in a process. Basically I might want to do multiple things at the same time to form a proper working-machine(process) that are somewhat independent parts(through threads). Each thread has certain information in Thread Control Block (TCB) which holds thread identifier, stack pointer, program counter, thread state, thread’s register set, parent’s process pointer. Multiple threads can exist within one process where:
- Each thread contains its own register set and local variables (stored in stack).
- All threads of a process share global variables (stored in heap) and the program code.

Multithreading is defined as the ability of a processor to execute multiple threads concurrently.
So basically in single core cpu, it will context switch between multiple threads and save a thread’s state everytime it stops one to start another whenever there is a manual or IO interrupt.
Multithreading example in Python
In this part, we demonstrate the difference between single thread process and multi-thread process with two components i.e. square calculation and cube calculation:
- Single Threaded Process: Execution Time: 0.801 sec
# This is an example of sequential programming
# where components are executed one by one.
# Imports
import time
# Components of a process
# calc_square and calc_cube
def calc_square(numbers):
for n in numbers:
print(f'\n{n} ^ 2 = {n*n}')
time.sleep(0.1)
def calc_cube(numbers):
for n in numbers:
print(f'\n{n} ^ 3 = {n*n*n}')
time.sleep(0.1)
numbers = [2, 3, 5, 8]
start = time.time()
# executing calc_square and calc_cube
# one after another!
calc_square(numbers)
calc_cube(numbers)
end = time.time()
print('Execution Time: {}'.format(end-start))
Multi Threaded Process: Execution Time: 0.402 sec
# Imports
import time
import threading
# Components of a process
# calc_square and calc_cube
def calc_square(numbers):
for n in numbers:
print(f'\n{n} ^ 2 = {n*n}')
time.sleep(0.1)
def calc_cube(numbers):
for n in numbers:
print(f'\n{n} ^ 3 = {n*n*n}')
time.sleep(0.1)
numbers = [2, 3, 5, 8]
start = time.time()
# executing calc_square and calc_cube
# in different threads!!
square_thread = threading.Thread(target=calc_square, args=(numbers,))
cube_thread = threading.Thread(target=calc_cube, args=(numbers,))
# starts execution of two threads!
square_thread.start()
cube_thread.start()
square_thread.join()
cube_thread.join()
end = time.time()
print('Execution Time: {}'.format(end-start))
In a Multi-Threaded process, we improve the time taken by program to run by half!! Multithreading allows us to execute the square and cube threads concurrently.
We use .start() to start thread’s execution and use .join() to tell which tells one thread to wait until other is complete.
It executes the calc_cube() function while the sleep method suspends calc_square() execution for 0.1 seconds, then it enters a sleep mode and executes the calc_square() function. Essentially, the operating system switches between the threads, running each one a little bit at a time, which improves the process’s runtime.
- Read more here: Link