课程 · 12 · 06 / 12
Threading and the GIL: Concurrent Python
Master threading in Python, understand the Global Interpreter Lock, use synchronization primitives, and know when threading helps vs. hurts.
TIPLearning Objectives: After this lesson, you'll understand threading in Python, the Global Interpreter Lock (GIL) and its implications, synchronization primitives, and when threading helps vs. hurts performance.
Understanding Concurrency vs Parallelism
Before diving into threading, let's clarify these often-confused concepts:
Basic Threading
Creating Threads
Daemon Threads
The Global Interpreter Lock (GIL)
TIP🎥 Watch this once and you'll get the GIL forever: David Beazley's Understanding the GIL talk (PyCon 2010). Live demos show exactly why CPU-bound multithreading goes nowhere in CPython, and why I/O-bound code still benefits. 38 minutes; pays back in saved debugging hours.
The GIL is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecode simultaneously.
Understanding the GIL
Use the memory visualizer above to see how threads share the same memory space. Now let's see the GIL's impact:
When Threading DOES Help: I/O-Bound Tasks
Synchronization Primitives
When multiple threads access shared data, we need synchronization.
Locks (Mutex)
RLock (Reentrant Lock)
Semaphore - Limited Resource Access
Event - Thread Signaling
Condition - Complex Coordination
Thread-Safe Data Structures
Thread Pooling
Practice Exercises
Exercise 1: Thread-Safe Cache
Exercise 2: Worker Pool with Results
Key Takeaways
| Concept | Description |
|---|---|
| GIL | Prevents true parallelism for CPU-bound Python code |
| Threading | Best for I/O-bound tasks (network, file, database) |
| Lock | Mutual exclusion, one thread at a time |
| RLock | Reentrant lock, same thread can acquire multiple times |
| Semaphore | Limit concurrent access to N threads |
| Event | Simple thread signaling |
| Condition | Complex thread coordination |
| Queue | Thread-safe producer-consumer pattern |
When to Use Threading
| Use Case | Threading Appropriate? |
|---|---|
| Network requests | Yes |
| File I/O | Yes |
| Database queries | Yes |
| CPU calculations | No (use multiprocessing) |
| GUI responsiveness | Yes |
| Web scraping | Yes |
Next Steps
In the next lesson, we'll explore Multiprocessing—bypass the GIL with true parallelism, use process pools, manage shared state, and understand inter-process communication.
Ready for true parallelism? Multiprocessing awaits!
Further Reading
The GIL — Required Watching
- David Beazley — Understanding the Python GIL — PyCon 2010. Still the clearest explanation of why the GIL exists and what it actually does. Pair with his follow-up PDF.
- Łukasz Langa — Removing the GIL (PEP 703) — what's coming in Python 3.13+ ("free-threaded Python").
Official Docs
- Python —
threadingmodule —Lock,RLock,Semaphore,Event,Condition,Barrier. - Python —
concurrent.futures— the modern high-level API. Reach forThreadPoolExecutorbefore rawThread. - Python —
queuemodule — thread-safe queues. The right way to share state between threads. - PEP 703 — Making the GIL Optional — the path to true parallelism.
Tutorials
- Real Python — Threading in Python — the canonical primer.
- Real Python —
concurrent.futures— comparing threading, multiprocessing, asyncio.
When Threading Wins (and When It Doesn't)
- CPU-bound → Threading is mostly useless under the GIL. Use
multiprocessingor write the hot path in C/Rust/numpy. - I/O-bound → Threading works, but
asynciois usually cleaner for hundreds-to-thousands of concurrent operations. - Mixed →
concurrent.futures.ThreadPoolExecutorfor compatibility with sync libraries.
Books
- Book: Fluent Python (2nd ed.) — Chapter 19 ("Concurrency Models in Python") — best single-chapter overview anywhere.
- Book: Python Concurrency with asyncio — Matthew Fowler. Covers the threading/asyncio boundary well.