Back to Python & Coding

PYTHON & CODING · QUESTION 80

What is the Python GIL, and how does it affect concurrency?

On this page
Intermediate 4 min read
Interview-ready answerThe concise version to remember

In standard CPython builds, the Global Interpreter Lock (GIL) allows only one thread at a time to execute Python bytecode within an interpreter, simplifying access to interpreter state. Threads can still overlap I/O because the lock is often released while waiting. CPU-bound Python work may not scale across threads; processes or suitable native libraries are alternatives.

LET'S MAKE IT SIMPLE

First, the idea in plain English

Threads let a program manage several tasks at once, but standard CPython uses a lock that limits parallel execution of Python code in one interpreter. While a thread waits for network or disk work, another can run, so threads remain useful for I/O. For CPU-heavy calculations, multiple processes may use multiple cores.

A USEFUL COMPARISON

Picture it this way

Imagine a workshop with several workers but only one shared precision tool that must be held by one worker at a time. Workers can take turns, and another worker can act while someone waits for a delivery. For independent heavy work, separate workshops can operate in parallel.

FOLLOW THE JOURNEY

I/O overlap differs from parallel Python bytecode execution

Contrast threads waiting on I/O with CPU-bound work under the standard CPython GIL.

I/O overlap differs from parallel Python bytecode executionContrast threads waiting on I/O with CPU-bound work under the standard CPython GIL.Concurrency comparison
01Start threadsCreate concurrent tasks that share one process and interpreter.
02Run Python codeThe GIL allows one thread at a time to execute Python bytecode in standard CPython.
03Wait or releaseI/O waits and some native operations release the lock.
04Choose execution modelUse processes or native parallel code for CPU-heavy work when suitable.

This simplified visual highlights the main relationships. In practice, the exact design depends on the requirements; The best approach depends on bottleneck and data-sharing needs.

Multiple threads share one interpreter lock for Python bytecode while waiting I/O can overlap; separate processes run in separate interpreters and can use multiple CPU cores.

How to read this visual
This simplified visual highlights the main relationships. In practice, the exact design depends on the requirements; The best approach depends on bottleneck and data-sharing needs.

UNDER THE HOOD

How it works, step by step

01

Start threads

Create concurrent tasks that share one process and interpreter.

Why it matters: Threads are lightweight and can share memory.

02

Run Python code

The GIL allows one thread at a time to execute Python bytecode in standard CPython.

Why it matters: This limits CPU-bound parallelism in that interpreter.

03

Wait or release

I/O waits and some native operations release the lock.

Why it matters: Other threads can make progress during waits.

04

Choose execution model

Use processes or native parallel code for CPU-heavy work when suitable.

Why it matters: The best approach depends on bottleneck and data-sharing needs.

OUTSIDE THE TEXTBOOK

A practical example

A program downloads hundreds of web pages. Threads can overlap network waits and improve throughput despite the GIL. If it instead performs CPU-heavy image transformations in pure Python, a process pool may use multiple cores, at the cost of inter-process communication and memory.

GO A LITTLE DEEPER

Technical details that matter

  • The GIL discussed here applies to standard CPython builds; Python implementations and newer optional free-threaded builds can differ.
  • Native extensions may release the GIL while doing work, enabling parallel compute in some libraries.
  • A lock does not make arbitrary application state race-free; synchronization and invariants still matter.

MAKE A GOOD CHOICE

When is this useful?

  • Choosing between threads and processes for concurrent workloads.
  • Explaining why I/O-bound Python often benefits from threads.
  • Diagnosing CPU utilization that does not scale with thread count.
Consider the alternative

Use `asyncio` for many concurrent I/O tasks with async-compatible libraries, or multiprocessing and vectorized native libraries for CPU work.

WATCH OUT FOR

Common misunderstandings

  • Saying Python cannot do concurrency at all.
  • Assuming threads speed up CPU-bound pure-Python loops.
  • Assuming the GIL removes every race condition in application logic.

REAL-WORLD TRADE-OFFS

Limitations and failure cases

  • Processes use more memory and require data transfer or shared-memory design.
  • Thread behavior depends on libraries and operations that release the lock.
  • Free-threaded configurations have different compatibility and performance trade-offs.

WHAT TO REMEMBER

Key takeaways

  1. 1The standard CPython GIL limits parallel Python bytecode per interpreter.
  2. 2Threads can overlap I/O waits.
  3. 3Use processes or native code for CPU parallelism where measured and appropriate.

PRACTICE THE FOLLOW-UP

What might an interviewer ask next?

Does the GIL make threads useless?

No. Threads can overlap I/O and coordinate background work; the limitation is CPU-bound Python bytecode running in parallel in one interpreter.

Is the GIL the same in every Python implementation?

No. It is an implementation detail of standard CPython builds; other implementations and free-threaded configurations may behave differently.

SAY IT OUT LOUD

How to explain this in an interview

“In standard CPython, the GIL allows one thread at a time to execute Python bytecode in an interpreter. Threads still help with I/O because they can overlap while one waits. For CPU-bound pure-Python work, processes or native libraries may provide parallelism. I would profile first and consider data-transfer and synchronization costs too.”

Continue your learning path

Connect this question to the roadmap topic it supports.

Open roadmap topic