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

Как GIL влияет на выполнение кода?

2.0 Middle🔥 161 комментариев
#Python Core#Асинхронность и многопоточность

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

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

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

Как GIL влияет на выполнение кода в Python

Global Interpreter Lock (GIL) — один из самых важных и обсуждаемых аспектов Python. Это фундаментальное ограничение, которое влияет на параллелизм.

Что такое GIL?

GIL — это мьютекс (взаимное исключение) в интерпретаторе CPython, который позволяет только одному потоку выполнять Python bytecode одновременно. Даже если у вас есть многоядерный процессор, только один поток может выполнять Python код в любой момент времени.

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

GIL был введен для упрощения управления памятью в CPython:

# CPython использует reference counting для управления памятью
class MyObject:
    pass

obj = MyObject()  # ref_count = 1
x = obj           # ref_count = 2
del x             # ref_count = 1
del obj           # ref_count = 0, объект удаляется

Без GIL каждое изменение reference count требовало бы дорогостоящей синхронизации между потоками. GIL решает эту проблему, разрешая одновременно только одному потоку работать с объектами.

Как GIL влияет на код?

1. CPU-bound операции: серьезные проблемы

import threading
import time

def cpu_bound_task():
    count = 0
    for i in range(50_000_000):
        count += i ** 2
    return count

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

# Двухпоточное выполнение (с 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} сек")  # ~16 сек! Медленнее!

Потоки замедляют выполнение из-за overhead переключения контекста.

2. I/O-bound операции: потоки работают отлично

import threading
import time
import requests

def fetch_url(url):
    response = requests.get(url)
    return len(response.text)

urls = [
    'https://example.com',
    'https://python.org',
    'https://github.com',
] * 5

# Однопоточно: ждем каждый запрос последовательно
start = time.time()
for url in urls:
    fetch_url(url)
print(f"Однопоточно: {time.time() - start:.2f} сек")  # ~15 сек

# Многопоточно: параллельные I/O операции
start = time.time()
threads = []
for url in urls:
    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} сек")  # ~3 сек! Быстрее!

Когда поток ждет I/O операцию, он отпускает GIL, позволяя другим потокам работать.

Влияние GIL на выбор технологии

CPU-bound работа:

import multiprocessing

# Вместо threading используй multiprocessing
with multiprocessing.Pool(processes=4) as pool:
    results = pool.map(cpu_bound_task, [10**7] * 4)

Каждый процесс имеет свой GIL, поэтому код будет работать в параллель.

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 await response.text()

async def main():
    tasks = [fetch_url(url) for url in urls]
    await asyncio.gather(*tasks)

asyncio.run(main())

asyncio эффективнее потоков для I/O, потому что не требует переключения контекста между потоками.

GIL и современный Python

Python 3.13+: Экспериментальный режим без GIL можно включить через --disable-gil. Это позволяет потокам работать параллельно без Глобального Лока:

python --disable-gil script.py

Практические выводы

Тип операцииЛучший выборПричина
CPU-boundmultiprocessingОбход GIL
I/O-boundasyncioНет overhead потоков
I/O-bound (простое)threadingЛегко писать
Долгие I/OCelery + multiprocessingРаспределенная работа
Смешанныеmultiprocessing + asyncioКомбинировать

Как минимизировать влияние GIL

  1. Используй C extensions: NumPy, pandas, scipy отпускают GIL
  2. Перепиши критичный код на Cython или PyO3
  3. Используй правильный инструмент: asyncio для I/O, multiprocessing для CPU
  4. Следи за Python 3.13+: Скоро GIL может уйти в историю