Concurrency: Threads and the GIL
Run overlapping work with threads, understand why the GIL limits them, and keep shared state correct with locks
Lock, or you get race conditions.
- distinguish concurrency from parallelism,
- start and join threads with the
threadingmodule, - explain what the GIL guarantees and what it costs,
- decide when threads help (I/O-bound) and when they do not (CPU-bound),
- spot a race condition and fix it with a
Lockorwith lock:, - reach for
ThreadPoolExecutorandqueue.Queueinstead of managing raw threads.
1. Concurrency is not the same as parallelism
Concurrency is a way of structuring a program so that several tasks are in progress at once — they can be interleaved on a single core, each making a little progress in turn. Parallelism is when tasks literally run at the same instant on multiple cores. Concurrency is about dealing with many things; parallelism is about doing many things simultaneously. Threads in CPython give you concurrency; because of the GIL they rarely give you parallelism for pure-Python CPU work.
This distinction is the key to the whole topic. Threads let a program wait on many things at once — twenty open sockets, ten files, five HTTP requests — so the total wall-clock time collapses toward the slowest single wait instead of the sum of all of them. What they cannot do is make one CPU-heavy Python loop finish faster.