Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Threads, the GIL, and what they cost

โญโญโญ advancedโณ 22 min read๐Ÿ“ Lesson 121 of 169

Know exactly when threads help, when they do nothing, and why they are not automatically safe.

Threads and the GIL: what actually happens

A thread shares memory with every other thread in the process. Python threads are real OS threads โ€” but in the standard CPython build, the GIL (Global Interpreter Lock) lets only one thread execute Python bytecode at a time.

The consequences, precisely:

  • CPU-bound pure-Python work gains nothing from threads. Summing a huge list in 4 threads takes the same time as 1 thread โ€” bytecode execution is serialized.
  • I/O-bound work gains a lot. While one thread waits on the network, disk, or time.sleep, the GIL is released and other threads run. Threads remain a fine model for concurrent I/O.
  • C extensions (NumPy, hashlib on large buffers, regex engines) often release the GIL during heavy calls โ€” so threads CAN parallelize some native code.
  • time.sleep releases the GIL. Waiting on queue.Queue, Lock, Event, Barrier releases it too.

Version note (prose): CPython 3.13 ships an experimental free-threaded build (PEP 703) without a GIL, where CPU-bound threads genuinely parallelize. The engineering skill โ€” measure, choose, verify โ€” is identical either way.

One more precision: the GIL does not make your code correct. It guarantees bytecode atomicity per instruction, but counter += 1 is three operations (load, add, store) โ€” another thread can interleave between them. That is the race you will repair in the first practice.