Introduction
Multithreading in Python allows you to run multiple threads (smaller units of a process) concurrently, making your program more efficient and responsive, especially for I/O-bound and high-level structured network code. Python provides the threading
module to work with threads.
- Thread: The smallest unit of execution within a process.
- Multithreading: Running multiple threads concurrently within a single process.
- The
threading
module: Multithreading in Python can be achieved using thethreading
module, which provides a high-level interface for creating and managing threads.
The threading Module
The threading
module provides a higher-level interface for working with threads.
Creating a Thread
You can create a thread by creating an instance of the Thread
class and passing a target function that the thread will execute.
Example
import threading
def print_numbers():
for i in range(1, 6):
print(i)
# Create a thread
thread = threading.Thread(target=print_numbers)
# Start the thread
thread.start()
# Wait for the thread to complete
thread.join()
print("Thread execution completed.")
Output
1
2
3
4
5
Thread execution completed.
Threading with Arguments
You can pass arguments to the target function using the args
parameter.
Example
import threading
def print_numbers(n):
for i in range(1, n+1):
print(i)
# Create a thread
thread = threading.Thread(target=print_numbers, args=(5,))
# Start the thread
thread.start()
# Wait for the thread to complete
thread.join()
print("Thread execution completed.")
Output
1
2
3
4
5
Thread execution completed.
Using Thread Subclass
You can also create a thread by subclassing the Thread
class and overriding the run
method.
Example
import threading
class NumberPrinter(threading.Thread):
def __init__(self, n):
super().__init__()
self.n = n
def run(self):
for i in range(1, self.n + 1):
print(i)
# Create a thread
thread = NumberPrinter(5)
# Start the thread
thread.start()
# Wait for the thread to complete
thread.join()
print("Thread execution completed.")
Output
1
2
3
4
5
Thread execution completed.
Synchronizing Threads
To avoid race conditions and ensure data integrity, you can use synchronization mechanisms like Locks, Events, Conditions, Semaphores, and Barriers.
Using Locks
A Lock
ensures that only one thread can access a shared resource at a time.
Example
import threading
class SharedCounter:
def __init__(self):
self.counter = 0
self.lock = threading.Lock()
def increment(self):
with self.lock:
self.counter += 1
print(f"Counter: {self.counter}")
counter = SharedCounter()
def worker():
for _ in range(5):
counter.increment()
# Create threads
threads = [threading.Thread(target=worker) for _ in range(3)]
# Start threads
for thread in threads:
thread.start()
# Wait for all threads to complete
for thread in threads:
thread.join()
print("All threads have finished execution.")
Output
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
Counter: 6
Counter: 7
Counter: 8
Counter: 9
Counter: 10
Counter: 11
Counter: 12
Counter: 13
Counter: 14
Counter: 15
All threads have finished execution.
Using Events
An Event
allows one thread to signal one or more other threads that some condition has occurred.
Example
import threading
import time
event = threading.Event()
def waiter():
print("Waiting for event to be set.")
event.wait()
print("Event has been set!")
def setter():
time.sleep(2)
print("Setting the event.")
event.set()
# Create threads
thread1 = threading.Thread(target=waiter)
thread2 = threading.Thread(target=setter)
# Start threads
thread1.start()
thread2.start()
# Wait for all threads to complete
thread1.join()
thread2.join()
print("All threads have finished execution.")
Output
Waiting for event to be set.
Setting the event.
Event has been set!
All threads have finished execution.
Using Condition
A Condition
allows one or more threads to wait until they are notified by another thread.
Example
import threading
condition = threading.Condition()
items = []
def consumer():
with condition:
while not items:
print("Consumer is waiting.")
condition.wait()
print("Consumer consumed item:", items.pop())
def producer():
with condition:
item = "item"
items.append(item)
print("Producer produced item:", item)
condition.notify_all()
# Create threads
consumer_thread = threading.Thread(target=consumer)
producer_thread = threading.Thread(target=producer)
# Start threads
consumer_thread.start()
producer_thread.start()
# Wait for all threads to complete
consumer_thread.join()
producer_thread.join()
print("All threads have finished execution.")
Output
Consumer is waiting.
Producer produced item: item
Consumer consumed item: item
All threads have finished execution.
Python threading Module Functions
The threading
module in Python provides a way to create and manage threads, allowing for concurrent execution of code. This can be useful for improving the performance of programs that perform multiple tasks simultaneously. Below is a list of some commonly used functions and classes in the threading
module, along with their descriptions and links to detailed guides for each function.
For a complete tutorial, visit Python threading Module Tutorial.
Table
Function/Class | Description |
---|---|
threading.Thread | A class for creating and managing individual threads. |
threading.Lock | A class for creating a lock object, used to ensure that only one thread accesses a resource at a time. |
threading.RLock | A reentrant lock that allows a thread to acquire the same lock multiple times. |
threading.Condition | A class for condition variables, which allow threads to wait for some condition to be met. |
threading.Event | A class for event objects, which allow threads to wait for an event to be set. |
threading.Semaphore | A class for semaphore objects, used to control access to a resource by a set number of threads. |
threading.BoundedSemaphore | A bounded semaphore that prevents the semaphore’s value from going above a specified maximum. |
threading.Timer | A class for creating a timer that runs a function after a specified interval. |
threading.Barrier | A class for creating a barrier that blocks threads until a specified number of threads have reached it. |
threading.local | A class for creating thread-local data, which is data that is unique to each thread. |
threading.active_count() | Returns the number of currently active threads. |
threading.current_thread() | Returns the current thread object. |
threading.enumerate() | Returns a list of all currently active thread objects. |
threading.main_thread() | Returns the main thread object. |
threading.get_ident() | Returns the current thread’s identifier. |
threading.get_native_id() | Returns the native integral thread ID of the current thread. |
threading.settrace() | Sets a trace function for all threads started from the threading module. |
threading.setprofile() | Sets a profile function for all threads started from the threading module. |
threading.stack_size() | Returns the size of the thread stack used when creating new threads. |
Conclusion
Multithreading in Python allows you to run multiple threads concurrently, making your programs more efficient and responsive. The threading
module provides various classes and methods to create, manage, and synchronize threads. Understanding and using these concepts effectively can help you build robust and efficient multithreaded applications.