In this tutorial, you’ll learn about multithreading in Python and how to create a thread in Python using the threading module. We’ll also cover thread synchronization with Python locks to manage shared resources efficiently. Each section includes step-by-step explanations with examples and sample code to help you understand the concepts easily.
Multithreading in Python: Everything You Need to Know
Multithreading is an essential concept in software programming, allowing multiple threads to run concurrently within a process. Most high-level languages, including Python, support multithreading to improve performance.
What is a Thread in Python?
In software programming, a thread is the smallest unit of execution within a process. It operates in the same memory space as other threads in the process, allowing efficient task execution. In Python, threads are managed using the threading module, which simplifies concurrent programming.
What is Multithreading in Python?
Multithreading allows a single process to execute multiple threads simultaneously. This can significantly improve performance for I/O-bound tasks, such as reading files, making API requests, or handling user input. Python’s threading module provides an easy way to create and manage threads, making it beginner-friendly.
Pros and Cons of Multithreading in Python
Multithreading lets your Python programs do more than one thing at the same time. But it has its ups and downs. Let’s break them down.
Advantages of Multithreading:
- Faster on Multi-Core Machines: When your computer has several cores or processors, multithreading can speed up your program. Each thread can run on a different core, making things run faster.
- Keeps Your Program Responsive: With multithreading, one thread can wait for user input while another keeps the program running (like updating a screen). This helps especially with programs that have a user interface.
- Easy Data Sharing: All threads in a program share the same global variables. If one thread changes a global variable, the other threads see that change immediately.
Disadvantages of Multithreading:
- Not Much Faster on Single-Core Systems: On computers with just one processor, multithreading might actually slow your program down because the extra work to manage threads can get in the way.
- Extra Work to Manage Data (Synchronization): When several threads use the same data, you need to use locks or other tools to make sure they don’t mess things up. This extra work can use more memory and CPU time.
- More Complex Code: Programs with many threads are harder to write and debug. It’s easier to make mistakes, like having two threads wait for each other forever (a deadlock) or one thread not getting enough time to run (starvation).
Well so far, you’ve read the theoretical concepts about threads. If you are new to Python, we would suggest you go through our 30 quick Python coding tips that can help you in writing Python multithreading code as well.
Multithreading in Python with Examples
Python gives you two modules to work with threads:
- <_thread> module
- <threading> module
Note: In Python 2, there was a module called thread, but in Python 3 it’s renamed to _thread for backward compatibility.
The main difference is:
- The _thread module lets you create a thread by calling a function.
- The threading module uses an object-oriented approach to create and manage threads.
Using ‘_thread’ Module to Create Threads in Python
If you decide to use the _thread module in your program, you can create threads with the following method.
#Syntax
_thread.start_new_thread(function, args[, kwargs])
- function: The function that the thread will run.
- args: A tuple of arguments to pass to that function. Use an empty tuple () if your function does not need any arguments.
- kwargs (optional): A dictionary of keyword arguments to pass to the function.
This method starts a new thread and returns its identifier. The thread will run the specified function with the given arguments. When the function finishes, the thread exits silently.
If the function ends with an unhandled error, a stack trace is printed for that thread, but the other threads keep running. This method works well on both Linux and Windows systems.
Python Multithreading Example Using _thread Module
from _thread import start_new_thread
from time import sleep
threadId = 1 # thread counter
waiting = 2 # waiting time in seconds
def factorial(n):
global threadId
if n < 1: # base case
print("{}: {}".format('\nThread', threadId))
threadId += 1
return 1
else:
result = n * factorial(n - 1) # recursive call
print("{} != {}".format(n, result))
return result
# Start two threads running the factorial function
start_new_thread(factorial, (5, ))
start_new_thread(factorial, (4, ))
print("Waiting for threads to return...")
sleep(waiting)
You can run the above code in your local Python terminal or use any online Python terminal. Once you execute this program, it’ll produce the following output.
Program output
Waiting for threads to return...
Thread: 1
1 != 1
2 != 2
3 != 6
4 != 24
5 != 120
Thread: 2
1 != 1
2 != 2
3 != 6
4 != 24
You can run this code in your local Python terminal or any online Python terminal. For more options, check out our article listing 7 of the best online Python terminals to test and run your code quickly.
Check out – Seven Best Online Python Interpreters
Using ‘threading’ Module to Create Threads in Python
The modern threading module in Python is a better and more powerful way to work with threads compared to the old _thread module. It gives you extra features and a cleaner, object-oriented approach.
It combines all the methods of the old _thread module and exposes a few additional methods.
- threading.activeCount(): Returns the total number of active threads.
- threading.currentThread(): Gives you the thread object that is currently running.
- threading.enumerate(): Returns a list of all active thread objects.
Apart from the above methods, the threading module also provides the Thread class. This class lets you create threads using an object-oriented method. Here are some its important methods:
Class Methods | Method Description |
---|---|
run(): | It is the entry point function for any thread. |
start(): | Starts the thread, which then calls the run() method automatically. |
join([time]): | Waits for the thread to finish. You can also specify a timeout. |
isAlive(): | Checks if the thread is still running. |
getName(): | Returns the name of the thread. |
setName(): | Sets or changes the name of the thread. |
For more details, you can check the official Python documentation.
Python Multithreading Example Using threading module
You may follow the below steps to implement a new thread:
- Construct a subclass from the Thread class.
- Override the <__init__(self [,args])> method to supply arguments as per requirements.
- Next, override the <run(self [,args])> method to code the business logic of the thread.
Once you define the new Thread subclass, you have to instantiate it to start a new thread. Then, invoke the start() method to initiate it. It will eventually call the run() method to execute the business logic.
Example – Create a thread class to print the date
#Python multithreading example to print current date. #1. Define a subclass using threading.Thread class. #2. Instantiate the subclass and trigger the thread. import threading import datetime class myThread (threading.Thread): def __init__(self, name, counter): threading.Thread.__init__(self) self.threadID = counter self.name = name self.counter = counter def run(self): print("\nStarting " + self.name) print_date(self.name, self.counter) print("Exiting " + self.name) def print_date(threadName, counter): datefields = [] today = datetime.date.today() datefields.append(today) print("{}[{}]: {}".format( threadName, counter, datefields[0] )) # Create new threads thread1 = myThread("Thread", 1) thread2 = myThread("Thread", 2) # Start new Threads thread1.start() thread2.start() thread1.join() thread2.join() print("\nExiting the Program!!!")
Program output
Output:
Starting Thread
Thread[1]: 2025-02-10
Exiting Thread
Starting Thread
Thread[2]: 2025-02-10
Exiting Thread
Exiting the Program!!!
Also Read: Socket Programming in Python
Using Locks for Synchronizing Threads in Python
The threading module has built-in functionality to implement locking that allows you to synchronize threads. Locking is required to control access to shared resources to prevent corruption or missed data.
You can call the Lock() method to apply locks, it returns the new lock object. Then, you can invoke the acquire(blocking) method of the lock object to enforce threads to run synchronously.
The optional blocking parameter specifies whether the thread waits to acquire the lock.
- Case blocking = 0: The thread would return immediately with a zero value if it fails to acquire the lock and with a one if the lock was successful.
- Case blocking = 1: The thread blocks and waits for the lock to be released.
The release() method of the lock object is used to release the lock when it is no longer required.
Just for your information, Python’s built-in data structures such as lists, and dictionaries are thread-safe as a side-effect of having atomic byte codes for manipulating them. Other data structures implemented in Python or basic types like integers and floats, don’t have that protection. To guard against simultaneous access to an object, we use a Lock object.
Multithreading Example for using Locks in Python
#Python multithreading example to demonstrate locking. #1. Define a subclass using threading.Thread class. #2. Instantiate the subclass and trigger the thread. #3. Implement locks in thread's run method. import threading import datetime exitFlag = 0 class myThread (threading.Thread): def __init__(self, name, counter): threading.Thread.__init__(self) self.threadID = counter self.name = name self.counter = counter def run(self): print("\nStarting " + self.name) # Acquire lock to synchronize thread threadLock.acquire() print_date(self.name, self.counter) # Release lock for the next thread threadLock.release() print("Exiting " + self.name) def print_date(threadName, counter): datefields = [] today = datetime.date.today() datefields.append(today) print("{}[{}]: {}".format( threadName, counter, datefields[0] )) threadLock = threading.Lock() threads = [] # Create new threads thread1 = myThread("Thread", 1) thread2 = myThread("Thread", 2) # Start new Threads thread1.start() thread2.start() # Add threads to thread list threads.append(thread1) threads.append(thread2) # Wait for all threads to complete for thread in threads: thread.join() print("\nExiting the Program!!!")
Program output
Output:
Starting Thread
Thread[1]: 2025-02-10
Exiting Thread
Starting Thread
Thread[2]: 2025-02-10
Exiting Thread
Exiting the Program!!!
Practice Quiz on Multithreading in Python
For practice, you should take up the below questionnaire. It would help you evaluate what you have learned from this tutorial.
However, you can also work on various Python exercises to boost your programming skills.
Conclusion: Multithreading in Python
We hope that you will find this Python Multithreading tutorial very interesting and helpful. The illustrations you found here will surely help in uplifting your Python skills.
If you liked this post, then please distribute it among your friend circle or on the social media platforms like (@techbeamers) you use.
Keep learning,
TechBeamers