What is Multithreading?
Multithreading runs multiple threads concurrently. In Python, it's best for I/O-bound tasks due to the Global Interpreter Lock (GIL).
Basic Threading
Use the threading module:
import threading
import time
def task(name, delay):
print(f"Task {name} starting")
time.sleep(delay)
print(f"Task {name} finished")
thread1 = threading.Thread(target=task, args=("A", 2))
thread2 = threading.Thread(target=task, args=("B", 1))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
ThreadPoolExecutor
Easier thread management:
from concurrent.futures import ThreadPoolExecutor
def download(url):
time.sleep(1)
return f"Downloaded {url}"
urls = ["url1", "url2", "url3"]
with ThreadPoolExecutor(max_workers=3) as executor:
results = executor.map(download, urls)
for result in results:
print(result)
Thread Safety
Use locks to prevent race conditions:
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
with lock:
counter += 1
When to Use
- I/O-bound tasks: Network, files
- Concurrent operations: Multiple independent tasks
- Avoid for CPU-bound: Use multiprocessing instead
Best Practices
- Use ThreadPoolExecutor: Easier than manual thread management
- Use locks: When sharing data between threads
- Don't overuse: Threads have overhead
- Consider async: Often simpler for I/O operations
Next Steps
Learn about multiprocessing for CPU-bound tasks.