Python

P
PythonHub
Progress 0%

Python

  • Home
  • History of Python
  • Applications of Python
  • Introduction To Python
    • What is Python
    • Character Set
    • Tokens in Python
    • Python Execution Mode
    • Variable And Identifiers
    • Data Types in Python
    • Operators And Expressions
    • Constants in Python
    • Assignment Statement
    • Input / Output in Python
    • Simple Python Scripts
    • Namespace in Python
    • πŸ“ Assignments
  • Operators in Python
    • Arithmetic Operators
    • Assignment Operators
    • Shorthand Assignment Operators
    • Relational Operators
    • Logical Operators
    • Bitwise Operators
    • Special Operators
    • πŸ“ Assignments
  • Input Output in Python
    • Accept Input
    • Output Formatting
    • πŸ“ Assignments
  • Conditional Statement
    • Decision Making
    • if Statement
    • IF-ELSE STATEMENT
    • IF-ELSE LADDER
    • NESTED IF-ELSE
    • Short Hand IF-ELSE
    • πŸ“ Assignments
  • Loops
    • Introduction to Loops
    • While Loop
    • Nested While Loop
    • πŸ“ While Loop Assignments
    • For Loop
    • For Loop Examples
    • Nested For Loop
    • Nested For Loop Examples
    • Infinite While Loops
    • Infinite For Loops
    • Break, Continue and Else in Loops
    • Difference Between For and While Loop
    • For Each Loop
    • πŸ“ For Each Assignments
    • πŸ“ All Loops Assignments
  • List
    • List in Python
    • Access List Elements
    • List Functions
    • Iterate (Loop) List
    • List Comprehension
    • πŸ“ Assignments
  • Tuple
    • Tuple in Python
    • Access Tuple Elements
    • Tuple Functions
    • Iterate (Loop) Tuple
    • Unpack Tuple
    • Tuple Comprehension
    • πŸ“ Assignments
  • Set
    • Set in Python
    • Access Set Elements
    • Set Methods
    • Iterate (Loop) Set
    • Pack/Unpack Set
    • Set Comprehension
    • πŸ“ Assignments
  • Dictionary
    • Dictionary
    • Access Dictionary Items
    • Dictionary Methods
    • Iterate (Loop) Dictionary
    • Formatting Dictionaries
    • Nested Dictionaries
    • Dictionary Comprehension
    • πŸ“ Assignments
  • Diff List Tuple Set Dictionary
    • List vs Tuple
    • List vs Set
    • List vs Dictionary
    • Tuple vs Set
    • Tuple vs Dictionary
    • Dictionary vs Set
    • πŸ“ Assignments
  • Exception
    • Error vs Exception
    • Types of Exception
    • Exception Handling
    • User Defined Exception
    • Logging Exception
    • πŸ“ Assignments
  • Functions
    • Introduction to Functions
    • Modular Programming
    • Types of Functions
    • Inbuilt Functions
    • Need For User-Defined Function
    • Elements of User Defined Function
    • Function Arguments
    • Nesting of Functions
    • Recursion
    • Global Local and Non Local
    • Python Lambda Functions
    • πŸ“ Assignments
  • Python Module
    • Introduction to Module
    • Inbuilt Modules in Python
    • User Defined Module
    • πŸ“ Assignments
  • File Handling
    • Introduction to Files
    • Create File
    • Read Files
    • Write to File
    • Rename File
    • Copy File
    • Move File
    • List Files in Directory
    • Binary Files
    • Zipping and Unzipping Files
    • πŸ“ Assignments
  • Strings
    • Basics of Strings
    • String Special Operators
    • String Formatting Operators
    • String Methods
    • πŸ“ Assignments
  • Regular Expressions
  • Python OOPS
    • Basics of Object Oriented
    • What are Classes and Objects?
    • Creating Class and Object
    • OOP vs Procedural Programming
    • Difference Between Classes and Objects
    • Constructors
    • Destructor
    • Built Class Methods and Attributes
    • Class and Instance Variables
    • Inheritance in Python
    • Single Inheritance
    • Multiple Inheritance
    • Multilevel Inheritance
    • Hierarchical Inheritance
    • Hybrid Inheritance
    • Abstraction
    • Method Overriding
    • Abstract Method
    • Interfaces in Python
    • Abstract Class vs Interface
    • Public, Private and Protected
    • Overloading vs Overriding
    • Inheritance vs Composition
    • Encapsulation
    • Polymorphism
    • Inner Classes
    • πŸ“ Assignments
  • Advanced Python
    • Iterator in Python
    • Generator in Python
    • Decorator in Python
    • Type Hints in Python
    • Async/Await Programming
    • Dataclasses in Python
    • Context Managers in Python
    • Property Decorator in Python
    • __slots__ in Python
    • Enums in Python
    • Walrus Operator in Python
    • Match-Case in Python
    • πŸ“ Assignments
  • Python Standard Library
    • Collections Module
    • Itertools Module
    • Functools Module
    • Datetime Module
    • JSON Module
    • OS Module
    • Sys Module
    • Random Module
    • Math Module
    • πŸ“ Assignments
  • Python Testing
    • Unit Testing in Python
    • Pytest Framework
    • Mocking in Python
    • πŸ“ Assignments
  • Python Best Practices
    • PEP 8 Style Guide
    • Docstrings in Python
    • Logging in Python
    • Code Optimization Tips
    • Debugging Techniques
    • πŸ“ Assignments
  • MySQL Database in Python
    • Introduction to MySQL with Python
    • DBMS vs File System
    • Connecting to MySQL Database
    • Create Database in MySQL
    • Create Table in MySQL
    • Insert Data in MySQL
    • Insert Multiple Rows
    • Select Data from MySQL
    • WHERE Clause in MySQL
    • Update Data in MySQL
    • Delete Data from MySQL
    • Parameterized Queries
    • Transaction Management
    • Error Handling
    • Connection Pooling
    • MySQL Drivers Guide
    • Joins in MySQL
    • Aggregation Functions
    • Backup MySQL Database
    • Best Practices
    • πŸ“ Assignments
  • MySQL Database Operations
    • SELECT Statement
    • MySQL Operators
    • DDL Statements
    • DML Statements
    • Subqueries
    • JOIN Operations
    • Aggregation
    • Case Study
    • πŸ“ Assignments
  • Graphics in Python
  • Threads in Python
    • Introduction to Threads
    • Process vs Threads
    • Concurrent Programming & GIL
    • Uses of Threads
    • Creating Threads
    • Single Tasking
    • Multi Tasking
    • Thread Synchronization
    • πŸ“ Assignments
  • Interview Questions & Answers
  • Python Case Studies
  • Multiple Choice Questions
  • πŸ“ Practice Problems
Get in Touch
  • tech2dsm@gmail.com

© Sankalan Data Tech

Python Language Interactive Tutorial

Python: Concurrent Programming & GIL

Python Concurrent Programming & GIL - Complete Guide

Understand concurrent programming and the Global Interpreter Lock in Python.

Created by Sankalan Data Tech Team Verified
Data Engineers, Analysts, Scientists & Trainers
Created by experienced Python developers, data engineers, and data scientists to make programming easy through practical examples, real-world experience, and clear explanations.
Read Time: 12 minutes Level: Advanced Topic: Python Concurrency Focus: GIL Explained
On this page:
  • What is Concurrent Programming?
  • What is the GIL?
  • How the GIL Works
  • Impact of the GIL
  • Working Around the GIL
  • GIL vs No GIL
  • Real-World Examples
  • Best Practices
  • Try It Yourself
  • Quiz
  • FAQ
Share this tutorial:
Twitter LinkedIn Facebook WhatsApp Reddit Telegram Email Copy Link
What You'll Learn Here
  • Concurrent programming β€” what it is and why it matters
  • The GIL β€” what it is and how it works
  • Impact on performance β€” how the GIL affects your code
  • Working around the GIL β€” strategies and best practices
  • Real-world examples β€” practical applications

What is Concurrent Programming?

Concurrent programming is about doing multiple things at the same time. It's like having multiple workers in a factory, each doing their own task simultaneously.

🏭 Think of it like a restaurant kitchen.

One chef (single-threaded) does everything: chops vegetables, cooks meat, plates dishes β€” one task at a time.

Multiple chefs (concurrent) work together: one chops vegetables, another cooks meat, another plates dishes β€” all at the same time. This is concurrent programming!

Concurrency

Multiple tasks making progress at the same time

Parallelism

Multiple tasks executing at exactly the same time

GIL

Global Interpreter Lock - limits Python concurrency

πŸ’‘ Key concept: Concurrency is about structure (multiple tasks interleaved), while parallelism is about execution (multiple tasks running simultaneously).

1

Concurrency vs Parallelism

# ============================================================
# CONCURRENCY vs PARALLELISM
# ============================================================

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ CONCURRENCY                                                   β”‚
β”‚ - Multiple tasks in progress at the same time                β”‚
β”‚ - Tasks are interleaved (not necessarily simultaneous)       β”‚
β”‚ - Example: A single-core CPU running multiple programs       β”‚
β”‚ - Benefits: Better resource utilization                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ PARALLELISM                                                  β”‚
β”‚ - Multiple tasks executing at exactly the same time          β”‚
β”‚ - Requires multiple CPU cores                                β”‚
β”‚ - Example: Multiple cores of a CPU running different tasks   β”‚
β”‚ - Benefits: Faster execution                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚              VISUAL EXAMPLE                β”‚
                 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                 β”‚                                             β”‚
                 β”‚  Single Core - Concurrency:                β”‚
                 β”‚  Task A β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘                   β”‚
                 β”‚  Task B β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆ                   β”‚
                 β”‚  Task C β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘                   β”‚
                 β”‚                                             β”‚
                 β”‚  Multi-Core - Parallelism:                 β”‚
                 β”‚  Task A β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ                  β”‚
                 β”‚  Task B β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ                  β”‚
                 β”‚  Task C β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ                  β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
""")

Key point: Concurrency is about dealing with multiple tasks; parallelism is about doing multiple tasks simultaneously.

Quick Check: What is the difference between concurrency and parallelism? (Answer: Concurrency is about structure; parallelism is about execution)

What is the GIL?

2

The Global Interpreter Lock Explained

The Global Interpreter Lock (GIL) is a mutex (lock) that prevents multiple threads from executing Python bytecode at the same time. It's a key feature of CPython (the standard Python implementation).

🚦 Think of it like a single-lane bridge.

Multiple cars (threads) want to cross the bridge. But only one car can cross at a time. The GIL is like the traffic light that allows only one car to cross at a time.

This makes Python's memory management simpler and safer, but it means CPU-bound threads can't run in parallel.

# ============================================================
# WHAT THE GIL DOES
# ============================================================

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ THE GIL IN ACTION                                             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  1. Thread 1 acquires the GIL                                  β”‚
β”‚  2. Thread 1 runs Python code                                  β”‚
β”‚  3. Thread 1 releases the GIL (after some time or I/O)        β”‚
β”‚  4. Thread 2 acquires the GIL                                  β”‚
β”‚  5. Thread 2 runs Python code                                  β”‚
β”‚  6. Thread 2 releases the GIL                                  β”‚
β”‚  7. ... repeats                                               β”‚
β”‚                                                                 β”‚
β”‚  Effect: Only one thread runs Python code at a time           β”‚
β”‚  Result: CPU-bound threads don't speed up on multi-core CPUs  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

WHY DOES THE GIL EXIST?

1. Memory Management
   - Python uses reference counting for garbage collection
   - The GIL prevents race conditions in reference counting

2. Simplicity
   - Makes CPython easier to maintain
   - Many C extensions assume the GIL exists

3. Performance
   - Single-threaded code runs faster (no lock overhead)
   - I/O-bound threads still benefit from threading
""")

GIL key points:

  • Mutex β€” prevents concurrent execution of Python bytecode
  • CPython only β€” other implementations (Jython, IronPython) don't have it
  • Not a bug β€” it's a design choice with trade-offs
  • I/O-bound benefits β€” threads still work for I/O

Quick Check: What does GIL stand for? (Answer: Global Interpreter Lock)

How the GIL Works

3

The GIL in Detail

# ============================================================
# HOW THE GIL WORKS - VISUALIZED
# ============================================================

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ GIL ACQUISITION AND RELEASE                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  Thread 1           Thread 2           Thread 3                β”‚
β”‚    β”‚                   β”‚                   β”‚                     β”‚
β”‚    β”‚ ◄─── GIL ────►   β”‚                   β”‚                     β”‚
β”‚    β”‚   (acquired)      β”‚                   β”‚                     β”‚
β”‚    β”‚                   β”‚                   β”‚                     β”‚
β”‚    β”‚  Running code     β”‚                   β”‚                     β”‚
β”‚    β”‚  (Python)         β”‚                   β”‚                     β”‚
β”‚    β”‚                   β”‚                   β”‚                     β”‚
β”‚    β”‚  ◄─── GIL ────►   β”‚                   β”‚                     β”‚
β”‚    β”‚   (released)      β”‚                   β”‚                     β”‚
β”‚    β”‚                   β”‚ ◄─── GIL ────►   β”‚                     β”‚
β”‚    β”‚                   β”‚   (acquired)      β”‚                     β”‚
β”‚    β”‚                   β”‚                   β”‚                     β”‚
β”‚    β”‚                   β”‚  Running code     β”‚                     β”‚
β”‚    β”‚                   β”‚  (Python)         β”‚                     β”‚
β”‚    β”‚                   β”‚                   β”‚                     β”‚
β”‚    β”‚                   β”‚  ◄─── GIL ────►   β”‚                     β”‚
β”‚    β”‚                   β”‚   (released)      β”‚                     β”‚
β”‚    β”‚                   β”‚                   β”‚ ◄─── GIL ────►     β”‚
β”‚    β”‚                   β”‚                   β”‚   (acquired)        β”‚
β”‚    β”‚                   β”‚                   β”‚                     β”‚
β”‚    β”‚                   β”‚                   β”‚  Running code       β”‚
β”‚    β”‚                   β”‚                   β”‚  (Python)           β”‚
β”‚                                                                 β”‚
β”‚  Time ──────────────────────────────────────────────────────►   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

WHEN DOES THE GIL RELEASE?

1. After executing a certain number of bytecode instructions
2. When a thread makes an I/O call (disk, network, etc.)
3. When a thread calls a C function (many libraries release the GIL)
4. When the thread is interrupted by the operating system
""")

GIL operation key points:

  • Acquired/released β€” each thread takes turns
  • I/O releases β€” GIL is released during I/O operations
  • Time-sliced β€” even CPU-bound threads get turns
  • C extensions β€” can release the GIL for performance

Quick Check: When does a thread release the GIL? (Answer: After bytecode execution, during I/O, or when calling certain C functions)

Impact of the GIL

4

How the GIL Affects Your Code

# ============================================================
# IMPACT OF THE GIL
# ============================================================

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ GIL IMPACT ON DIFFERENT TASKS                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  CPU-BOUND TASKS                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Impact: NEGATIVE                                       β”‚   β”‚
β”‚  β”‚  Why: Threads can't run in parallel                    β”‚   β”‚
β”‚  β”‚  Example: Heavy calculations, image processing         β”‚   β”‚
β”‚  β”‚  Solution: Use multiprocessing                         β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                 β”‚
β”‚  I/O-BOUND TASKS                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Impact: POSITIVE                                       β”‚   β”‚
β”‚  β”‚  Why: Threads release GIL during I/O                    β”‚   β”‚
β”‚  β”‚  Example: Network requests, file operations             β”‚   β”‚
β”‚  β”‚  Solution: Use threading                                β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                 β”‚
β”‚  MIXED TASKS                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Impact: MIXED                                          β”‚   β”‚
β”‚  β”‚  Why: Some parts CPU-bound, some I/O-bound             β”‚   β”‚
β”‚  β”‚  Example: Web scraping with processing                  β”‚   β”‚
β”‚  β”‚  Solution: Use both threading and multiprocessing      β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

# ============================================================
# REAL PERFORMANCE COMPARISON
# ============================================================

# CPU-Bound Task - Single vs Multi-Thread
# With GIL: Multi-thread is SLOWER than single-thread
# Because: Thread switching overhead

# I/O-Bound Task - Single vs Multi-Thread
# With GIL: Multi-thread is MUCH FASTER than single-thread
# Because: Threads release GIL during I/O waits
""")

GIL impact summary:

  • CPU-bound β€” GIL hurts performance
  • I/O-bound β€” GIL has little impact (threads work well)
  • Mixed β€” depends on the ratio of CPU to I/O

Quick Check: Does the GIL affect I/O-bound tasks? (Answer: No, threads release the GIL during I/O)

Working Around the GIL

5

Strategies to Bypass the GIL

# ============================================================
# WORKAROUNDS FOR THE GIL
# ============================================================

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STRATEGY 1: USE MULTIPROCESSING                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  from multiprocessing import Process, Pool                     β”‚
β”‚  - Each process has its own Python interpreter                 β”‚
β”‚  - Each process has its own GIL                                β”‚
β”‚  - True parallelism on multi-core CPUs                         β”‚
β”‚  - Higher overhead (memory, startup time)                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STRATEGY 2: USE C EXTENSIONS                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  import numpy as np                                            β”‚
β”‚  import pandas as pd                                           β”‚
β”‚  - Many C libraries release the GIL                           β”‚
β”‚  - NumPy, Pandas, SciPy do heavy lifting in C                β”‚
β”‚  - Excellent for numerical computing                           β”‚
β”‚  - Uses true parallelism                                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STRATEGY 3: USE ASYNCIO                                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  import asyncio                                                β”‚
β”‚  - Single-threaded concurrency                                β”‚
β”‚  - Uses event loop instead of threads                         β”‚
β”‚  - Great for I/O-bound tasks                                  β”‚
β”‚  - No GIL issues                                              β”‚
β”‚  - Lower overhead than threads                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STRATEGY 4: USE OTHER PYTHON IMPLEMENTATIONS                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  - Jython (Java) - no GIL                                     β”‚
β”‚  - IronPython (.NET) - no GIL                                 β”‚
β”‚  - PyPy (has GIL but better performance)                     β”‚
β”‚  - Not always practical                                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
""")

# ============================================================
# PRACTICAL EXAMPLE - MULTIPROCESSING
# ============================================================

print("\n" + "=" * 40)
print("MULTIPROCESSING EXAMPLE:")
print("=" * 40)

print("""
from multiprocessing import Pool

def cpu_intensive_task(n):
    # Heavy computation
    return sum(i*i for i in range(n))

# Using multiple processes
with Pool(processes=4) as pool:
    results = pool.map(cpu_intensive_task, [1000000] * 4)
    print(results)
""")

GIL workarounds summary:

  • Multiprocessing β€” bypasses the GIL completely
  • C extensions β€” many release the GIL
  • asyncio β€” single-threaded concurrency
  • Other implementations β€” Jython, IronPython

Quick Check: What is the most common way to bypass the GIL? (Answer: Using multiprocessing)

GIL vs No GIL

6

Comparison of Python Implementations

Feature CPython (GIL) Jython (No GIL) IronPython (No GIL) PyPy (GIL)
GIL Yes No No Yes
Threading I/O-bound only True parallelism True parallelism I/O-bound only
Multi-core Limited Full Full Limited
Speed Fast (C) Medium (Java) Medium (.NET) Fast (JIT)
Compatibility Excellent Limited Limited Good
Use Cases General Java integration .NET integration Performance

Comparison key points:

  • CPython β€” most common, has GIL
  • Jython/IronPython β€” no GIL but less common
  • PyPy β€” has GIL but faster JIT
  • Choice matters β€” pick based on your needs

Quick Check: Which Python implementation has no GIL? (Answer: Jython and IronPython)

Real-World Examples

7

GIL in Action - Performance Comparison

# ============================================================
# GIL PERFORMANCE COMPARISON
# ============================================================

import time
import threading
from multiprocessing import Pool

# ============================================================
# CPU-BOUND TASK
# ============================================================

def cpu_heavy(n=10000000):
    """CPU-intensive task"""
    result = 0
    for i in range(n):
        result += i * i
    return result

print("=" * 60)
print("CPU-BOUND TASK PERFORMANCE")
print("=" * 60)

# Single thread
start = time.time()
cpu_heavy()
single_time = time.time() - start
print(f"Single thread: {single_time:.2f}s")

# Multi-thread (GIL limited)
def run_threads(num_threads=4):
    threads = []
    for i in range(num_threads):
        t = threading.Thread(target=cpu_heavy, args=(2500000,))
        threads.append(t)
        t.start()
    for t in threads:
        t.join()

start = time.time()
run_threads()
thread_time = time.time() - start
print(f"Multi-thread: {thread_time:.2f}s")

# Multi-process (Bypasses GIL)
def run_processes(num_processes=4):
    with Pool(processes=num_processes) as pool:
        pool.map(cpu_heavy, [2500000] * num_processes)

start = time.time()
run_processes()
process_time = time.time() - start
print(f"Multi-process: {process_time:.2f}s")

print(f"\nSpeedup (processes vs threads): {thread_time/process_time:.2f}x")

# ============================================================
# I/O-BOUND TASK
# ============================================================

print("\n" + "=" * 60)
print("I/O-BOUND TASK PERFORMANCE")
print("=" * 60)

def io_task(delay=0.5):
    """Simulate I/O task"""
    time.sleep(delay)
    return "Done"

print("""
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OBSERVATIONS:                                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ CPU-bound tasks: Processes are much faster than threads      β”‚
β”‚ β€’ I/O-bound tasks: Threads and processes perform similarly    β”‚
β”‚ β€’ The GIL only limits CPU-bound work                          β”‚
β”‚ β€’ Choose the right tool for your task type                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

RECOMMENDATIONS:
β€’ CPU-intensive work β†’ Use multiprocessing
β€’ I/O-intensive work β†’ Use threading
β€’ Mixed work β†’ Use both or ThreadPoolExecutor
β€’ Numerical computing β†’ Use NumPy (C releases GIL)
""")

Real-world example key points:

  • CPU-bound β€” processes are much faster
  • I/O-bound β€” threads work well
  • Speedup β€” processes can be 2-4x faster for CPU work
  • Choose wisely β€” pick based on task type

Quick Check: Which is faster for CPU-bound tasks: threads or processes? (Answer: Processes)

Best Practices

8

Working with the GIL - Best Practices

# ============================================================
# GIL BEST PRACTICES
# ============================================================

print("1. KNOW YOUR TASK TYPE")
print("   - CPU-bound β†’ multiprocessing")
print("   - I/O-bound β†’ threading")
print("   - Mixed β†’ use both")

print("\n2. USE APPROPRIATE LIBRARIES")
print("   - NumPy, Pandas for numerical work (release GIL)")
print("   - asyncio for many concurrent I/O operations")
print("   - concurrent.futures for thread/process pools")

print("\n3. MEASURE BEFORE OPTIMIZING")
print("   - Profile your code")
print("   - Don't assume GIL is the problem")
print("   - Measure with and without threading")

print("\n4. USE PROCESS POOLS FOR CPU WORK")
print("   - from multiprocessing import Pool")
print("   - Reuse processes")
print("   - Map/reduce pattern")

print("\n5. USE THREAD POOLS FOR I/O WORK")
print("   - from concurrent.futures import ThreadPoolExecutor")
print("   - Manage many connections")
print("   - Web scraping, API calls")

print("\n6. CONSIDER ASYNCIO FOR HIGH CONCURRENCY")
print("   - Thousands of connections")
print("   - Event loop model")
print("   - No GIL issues")

print("\n7. KEEP THREADS SHORT")
print("   - Release GIL often")
print("   - Use small tasks")
print("   - Avoid long-running CPU work in threads")

Best practices summary:

  • Know your task β€” CPU vs I/O
  • Use right library β€” NumPy for numerical work
  • Measure first β€” profile before optimizing
  • Use pools β€” for managing many tasks

Quick Check: What library should you use for numerical computing? (Answer: NumPy, which releases the GIL)

Try It Yourself

Experiment with the GIL in the editor below.

Loading Pyodide... 0%
Python Code Editor
========================================
GIL - PRACTICE
========================================

1. GIL SIMULATION - CPU WORK
----------------------------------------
Thread A starts CPU work...
GIL acquired by Thread-A
Thread-A: Working... (CPU)
Thread-A: CPU work 1
Thread-A: CPU work 2
Thread-A: CPU work 3
GIL released by Thread-A
Thread B starts CPU work...
GIL acquired by Thread-B
Thread-B: Working... (CPU)
Thread-B: CPU work 1
Thread-B: CPU work 2
Thread-B: CPU work 3
GIL released by Thread-B

2. GIL SIMULATION - I/O WORK
----------------------------------------
Thread C starts I/O work...
GIL acquired by Thread-C
Thread-C: Working... (I/O)
Thread-C: I/O starting - releasing GIL
GIL released by Thread-C
GIL acquired by Thread-C
Thread-C: I/O completed
GIL released by Thread-C
Thread D starts I/O work...
GIL acquired by Thread-D
Thread-D: Working... (I/O)
Thread-D: I/O starting - releasing GIL
GIL released by Thread-D
GIL acquired by Thread-D
Thread-D: I/O completed
GIL released by Thread-D

3. GIL SUMMARY
----------------------------------------
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Concept β”‚ Impact β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ GIL β”‚ Only one thread runs Python code at a time β”‚
β”‚ CPU Work β”‚ Threads are limited by GIL β”‚
β”‚ I/O Work β”‚ Threads release GIL during I/O β”‚
β”‚ Multiprocessingβ”‚ Bypasses GIL completely β”‚
β”‚ C Extensions β”‚ Many release GIL for performance β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Understanding the GIL helps you write efficient concurrent code!
πŸ†

You've Got It!

You now understand concurrent programming and the Global Interpreter Lock in Python. You know how the GIL works, its impact, and how to work around it.

Quick Quiz

Test what you've learned:

1. What does GIL stand for?
2. What does the GIL prevent?
3. Which type of task does the GIL affect most?
4. What is the most common way to bypass the GIL?
5. Which Python implementation does NOT have a GIL?

Frequently Asked Questions

Why does Python have a GIL? β–Ό

The GIL exists to simplify memory management in CPython. It prevents race conditions in Python's reference counting garbage collector, making CPython simpler and more reliable. It also makes C extensions easier to write.

Can I remove the GIL from Python? β–Ό

You can't remove the GIL from CPython, but you can use other implementations like Jython or IronPython that don't have a GIL. You can also bypass it using multiprocessing or C extensions that release the GIL.

What is a common interview question about the GIL? β–Ό

Common questions include: "What is the GIL and how does it affect Python threading?" "Why does Python have a GIL?" "How do you work around the GIL?" and "When are threads useful in Python despite the GIL?"

Does NumPy bypass the GIL? β–Ό

Yes! NumPy performs its heavy computations in C and releases the GIL during those operations. This allows NumPy to achieve true parallelism even with the GIL.

What is the difference between concurrency and parallelism? β–Ό

Concurrency is about dealing with multiple tasks at the same time (structure). Parallelism is about executing multiple tasks at exactly the same time (execution). Concurrency is about management; parallelism is about execution.

Where to Go From Here

Now that you understand concurrent programming and the GIL, check out these related topics:

Uses of Threads

Learn practical applications of threading.

Learn More β†’

Creating Threads

Deep dive into creating and managing threads.

Learn More β†’

Thread Synchronization

Learn how to safely share data between threads.

Learn More β†’
Interview Resources
  • Python Syntax & Variables Interview Questions
  • Top SQL Interview Questions & Answers
  • SQL Joins: Displaying Data from Multiple Tables FAQ
  • Python Lists and Dictionaries Interview Questions
  • Python OOP Interview Questions
  • SQL Set Operators Interview Questions
Previous: Process vs Threads Next: Uses of Threads β†’