What is Threading and Multithreading in Python?
Threading and multithreading are techniques in Python that allow you to
execute multiple tasks
concurrently within a single process. This approach helps improve performance,
especially in I/O-bound applications.
What is a Thread?
A thread is the smallest unit of a process that can be scheduled and executed
by the operating system. By default, Python programs execute as a
single-threaded process. However, the threading
module allows you
to create and manage multiple threads.
What is Multithreading?
Multithreading is the process of running multiple threads concurrently in a single program. It is particularly useful in:
- Performing multiple I/O tasks (e.g., reading files, making network requests).
- Keeping the application responsive (e.g., in GUI applications).
Note: Python's Global Interpreter Lock (GIL) may limit the benefits of multithreading in CPU-bound tasks. For such tasks, multiprocessing is a better alternative.
Threading in Python
Python provides the threading
module to work with threads. Let’s
explore its usage with examples.
Basic Example of Threading
The following code demonstrates how to create and start a thread in Python.
import threading
import time
def print_numbers():
for i in range(1, 6):
print(f"Number: {i}")
time.sleep(1)
# Creating a thread
thread = threading.Thread(target=print_numbers)
# Starting the thread
thread.start()
# Main thread execution
print("Main thread is running...")
# Waiting for the thread to complete
thread.join()
print("Thread has finished execution!")
Output:
Main thread is running...
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Thread has finished execution!
Multithreading with Multiple Threads
You can run multiple threads simultaneously using the
threading
module.
import threading
import time
def print_task(task_name):
for i in range(1, 4):
print(f"{task_name} - Step {i}")
time.sleep(1)
# Creating multiple threads
thread1 = threading.Thread(target=print_task, args=("Task 1",))
thread2 = threading.Thread(target=print_task, args=("Task 2",))
# Starting the threads
thread1.start()
thread2.start()
# Waiting for both threads to complete
thread1.join()
thread2.join()
print("Both tasks completed!")
Output:
Task 1 - Step 1
Task 2 - Step 1
Task 1 - Step 2
Task 2 - Step 2
Task 1 - Step 3
Task 2 - Step 3
Both tasks completed!
Using Locks to Prevent Race Conditions
When multiple threads access shared resources, race conditions can occur.
Python's threading
module provides a Lock
object to
synchronize threads and avoid such issues.
import threading
balance = 0
lock = threading.Lock()
def deposit(amount):
global balance
for _ in range(1000000):
with lock: # Acquire and release the lock automatically
balance += amount
def withdraw(amount):
global balance
for _ in range(1000000):
with lock:
balance -= amount
# Creating threads
thread1 = threading.Thread(target=deposit, args=(1,))
thread2 = threading.Thread(target=withdraw, args=(1,))
# Starting threads
thread1.start()
thread2.start()
# Waiting for threads to finish
thread1.join()
thread2.join()
print(f"Final Balance: {balance}")
Output:
Final Balance: 0
Real-World Example of Multithreading
Here’s an example of using multithreading to fetch data from multiple websites concurrently:
import threading
import requests
def fetch_url(url):
response = requests.get(url)
print(f"Fetched {url} with status: {response.status_code}")
urls = [
"https://www.google.com",
"https://www.python.org",
"https://www.github.com"
]
# Creating threads for each URL
threads = [threading.Thread(target=fetch_url, args=(url,)) for url in urls]
# Starting threads
for thread in threads:
thread.start()
# Waiting for threads to finish
for thread in threads:
thread.join()
Advantages of Multithreading
- Concurrency: Threads allow multiple tasks to run concurrently.
- Responsiveness: Applications remain responsive while performing time-consuming tasks.
- Resource Sharing: Threads within a process share the same memory space.
Conclusion
Threading and multithreading in Python provide a powerful way to manage multiple tasks simultaneously, especially for I/O-bound applications. While Python’s GIL may limit multithreading for CPU-bound tasks, threading remains a vital tool for improving program efficiency in the right scenarios.
Comments
Post a Comment