🧵 Multithreading and Semaphores in Python
Multithreading allows a program to run multiple operations concurrently. However, in Python, the Global Interpreter Lock (GIL) limits true parallelism for CPU-bound tasks, making threading most effective for I/O-bound tasks.
🧵 The threading Module
The threading module allows you to create and manage threads.
import threading
import time
def worker(name):
print(f"{name} starting")
time.sleep(1)
print(f"{name} exiting")
t1 = threading.Thread(target=worker, args=("Thread-1",))
t2 = threading.Thread(target=worker, args=("Thread-2",))
t1.start()
t2.start()
t1.join() # Wait for completion
t2.join()
🚦 Synchronization Primitives
When threads share data, race conditions can occur. Synchronization primitives help prevent this.
🔒 Locks
A Lock ensures that only one thread can access a resource at a time.
lock = threading.Lock()
counter = 0
def increment():
global counter
with lock:
counter += 1
🚩 Semaphores
A Semaphore manages an internal counter. It allows a fixed number of threads to access a resource simultaneously.
import threading
import time
semaphore = threading.Semaphore(2) # Allow 2 threads at a time
def access_resource(id):
print(f"Thread {id} waiting")
with semaphore:
print(f"Thread {id} acquired semaphore")
time.sleep(2)
print(f"Thread {id} released semaphore")
threads = []
for i in range(5):
t = threading.Thread(target=access_resource, args=(i,))
threads.append(t)
t.start()
This is useful for limiting connections to a database or API.
🏊 ThreadPoolExecutor
The concurrent.futures module provides a high-level interface for asynchronously executing callables.
from concurrent.futures import ThreadPoolExecutor
def task(n):
return n * n
with ThreadPoolExecutor(max_workers=3) as executor:
results = executor.map(task, range(5))
print(list(results)) # [0, 1, 4, 9, 16]
📝 Summary
- ✅ GIL: Python's Global Interpreter Lock prevents multiple native threads from executing Python bytecodes at once.
- ✅ I/O Bound: Threading is great for network requests, file I/O.
- ✅ Locks: Prevent race conditions by ensuring mutual exclusion.
- ✅ Semaphores: Control access to a resource with limited capacity.
- ✅ ThreadPoolExecutor: Easier management of a pool of threads.
Created with ❤️ by Pynfinity