What is the Global Interpreter Lock in Python, and what does it stop you from doing?
The Global Interpreter Lock is a mutex inside the CPython interpreter. Only one thread can be executing Python bytecode at any moment, so two threads in one process cannot run Python code in parallel.
What it does not stop is the concurrency that actually matters for most applications. A thread that is blocked on I/O — reading a socket, waiting on a database, sleeping — releases the GIL, so other threads keep running while it waits. That is why threads are the right tool for I/O-bound work: a thousand threads waiting on network responses can all be in flight in one process, and the GIL only matters while one of them is actually computing.
What it does stop is parallel execution of CPU-bound Python code. Two threads each running a tight numerical loop will not finish in half the time, because they take turns holding the lock rather than running at the same time. The same work in two processes does run in parallel, because each process has its own interpreter and its own GIL.
Two clarifications to have ready. The GIL is an implementation detail of CPython, not a language guarantee, and CPython 3.13 and later have work in progress to make it optional so that free-threaded builds can run Python code truly in parallel. And the GIL is per-interpreter, not global across the machine — several processes can run Python code simultaneously on different cores. That is why multiprocessing, rather than threading, is the answer for CPU-bound work in Python.