← Назад к вопросам

Что такое Global Interpreter Lock в Python?

2.0 Middle🔥 281 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Global Interpreter Lock в Python

Global Interpreter Lock (GIL) — это мьютекс (взаимное исключение), который защищает доступ к объектам в CPython (стандартной реализации Python). GIL гарантирует, что только один поток может выполнять байт-код Python одновременно, даже на многоядерных системах.

Почему существует GIL

CPython управляет памятью через reference counting (подсчёт ссылок). Каждый объект имеет счётчик ссылок:

import sys

x = [1, 2, 3]
print(sys.getrefcount(x))  # Количество ссылок на объект

y = x  # Увеличивает счётчик
del x  # Уменьшает счётчик

# Когда счётчик = 0, объект удаляется из памяти

Если несколько потоков будут одновременно изменять счётчик, возникнет race condition. Вместо того чтобы использовать дорогой мьютекс для каждого объекта, CPython использует один глобальный мьютекс — GIL.

Последствия GIL

Многопоточность не даёт параллелизм для CPU-bound операций:

import threading
import time

def cpu_bound_task():
    """CPU-интенсивная операция"""
    total = 0
    for i in range(100_000_000):
        total += i
    return total

# Однопоточное выполнение
start = time.time()
cpu_bound_task()
cpu_bound_task()
print(f"Однопоточно: {time.time() - start:.2f}s")  # ~4 сек

# Многопоточное выполнение (с GIL)
start = time.time()
t1 = threading.Thread(target=cpu_bound_task)
t2 = threading.Thread(target=cpu_bound_task)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"Многопоточно: {time.time() - start:.2f}s")  # ~8 сек (!)

Многопоточность даже медленнее из-за overhead переключения контекста!

Когда GIL не проблема

I/O-bound операции: GIL отпускается во время I/O:

import threading
import time
import requests

def fetch_url(url):
    """I/O-bound операция"""
    response = requests.get(url)
    return response.status_code

# Многопоточное выполнение
start = time.time()
threads = []
for url in ["http://example.com"] * 10:
    t = threading.Thread(target=fetch_url, args=(url,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

print(f"Время: {time.time() - start:.2f}s")  # Намного быстрее!

Во время ожидания ответа от сервера другие потоки могут работать.

Решения для CPU-bound операций

1. multiprocessing (отдельные процессы, каждый со своим GIL):

from multiprocessing import Pool

def cpu_bound_task():
    total = 0
    for i in range(100_000_000):
        total += i
    return total

if __name__ == "__main__":
    with Pool(processes=2) as pool:
        results = pool.map(cpu_bound_task, [None, None])
        # Выполнится на двух ядрах параллельно (~4 сек, не 8)

2. asyncio (для I/O-bound операций):

import asyncio
import aiohttp

async def fetch_url(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return response.status

async def main():
    urls = ["http://example.com"] * 10
    tasks = [fetch_url(url) for url in urls]
    results = await asyncio.gather(*tasks)
    return results

asyncio.run(main())

3. Написать критичный код на C (NumPy, расширения на C):

import numpy as np

# NumPy операции отпускают GIL
x = np.array([1, 2, 3]) * 1_000_000
y = np.array([4, 5, 6]) * 1_000_000

# Это будет параллельным, не ограничено GIL
result = np.dot(x, y)

Python 3.13: No-GIL режим

Python сообщество понимает проблему. В Python 3.13 планируется экспериментальная поддержка --disable-gil:

python3.13 --disable-gil script.py

Это позволит использовать многопоточность для CPU-bound операций, но может немного замедлить однопоточный код.

Best Practices

  1. Для I/O-bound: используй threading или asyncio
  2. Для CPU-bound: используй multiprocessing или asyncio с библиотеками, которые отпускают GIL
  3. Профилируй перед оптимизацией
  4. Помни: GIL — особенность реализации CPython. PyPy, Jython, IronPython его не имеют

GIL — это компромисс между простотой реализации и производительностью однопоточного кода. Понимание этого механизма критично для написания правильно масштабируемых приложений.

Что такое Global Interpreter Lock в Python? | PrepBro