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

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

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

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

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

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

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

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

Что такое GIL?

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

import threading
import time

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

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

# Многопоточное выполнение
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")

В этом примере многопоточное выполнение будет медленнее, чем однопоточное, из-за GIL!

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

  1. Управление памятью: CPython использует подсчёт ссылок (reference counting) для управления памятью. Без GIL пришлось бы добавлять блокировки к каждому объекту, что было бы неэффективно.

  2. Простота расширений: C расширениям легче работать с GIL, не беспокоясь о синхронизации.

  3. Производительность однопоточного кода: GIL позволяет CPython быть эффективнее в однопоточном сценарии.

На какие операции НЕ влияет GIL?

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

import threading
import time
import requests

def fetch_url(url):
    # GIL отпускается во время сетевого запроса
    response = requests.get(url)
    return len(response.content)

start = time.time()
t1 = threading.Thread(target=fetch_url, args=("https://example.com",))
t2 = threading.Thread(target=fetch_url, args=("https://example.com",))
t1.start()
t2.start()
t1.join()
t2.join()
print(f"I/O задачи: {time.time() - start:.2f}s")

Для I/O-интенсивных задач (сетевые запросы, работа с файлами) многопоточность очень эффективна.

Решения для обхода GIL

1. Multiprocessing вместо Threading:

from multiprocessing import Process

def cpu_bound():
    total = 0
    for i in range(50000000):
        total += i
    return total

if __name__ == "__main__":
    p1 = Process(target=cpu_bound)
    p2 = Process(target=cpu_bound)
    p1.start()
    p2.start()
    p1.join()
    p2.join()

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

2. Использование asyncio для I/O:

import asyncio
import aiohttp

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, "https://example.com") for _ in range(10)]
        results = await asyncio.gather(*tasks)
        return results

3. C расширения: NumPy, Pandas и другие библиотеки выпускают GIL во время выполнения векторных операций.

Python 3.13+ — конец GIL?

V Python 3.13 экспериментально добавлена опция --disable-gil, которая позволяет запустить CPython без GIL. Это большой шаг в эволюции Python.

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

  • Для CPU-bound задач: используй multiprocessing
  • Для I/O-bound задач: используй threading или asyncio
  • Для параллельных вычислений: NumPy/Pandas (выпускают GIL)
  • Переходить на другие реализации: PyPy, Jython, IronPython не имеют GIL