Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
GIL (Global Interpreter Lock) — когда отдаёт управление
GIL в Python отдаёт управление другим потокам в трёх основных случаях:
1. После выполнения определённого количества инструкций
По умолчанию GIL переключается каждые 100 инструкций Python (в Python 3.13+ эта поведение изменилось).
import sys
# Просмотр текущего лимита
print(sys.getcheckinterval()) # Было 100 в Python < 3.2
# В Python 3.2+ используется sys.setswitchinterval()
print(sys.getswitchinterval()) # По умолчанию 0.005 сек (5 мс)
# Изменение интервала
sys.setswitchinterval(0.001) # Чаще переключаться
2. При блокирующих I/O операциях
Это самый важный случай — GIL отдаётся на время I/O:
import threading
import time
import requests
def fetch_data(url):
print(f"Поток {threading.current_thread().name} начал запрос")
# GIL ОТДАН на время HTTP запроса!
response = requests.get(url)
print(f"Поток {threading.current_thread().name} получил ответ")
return response
# Два потока могут работать параллельно при I/O
t1 = threading.Thread(target=fetch_data, args=("http://example.com",))
t2 = threading.Thread(target=fetch_data, args=("http://google.com",))
t1.start()
t2.start()
t1.join()
t2.join()
# Обе операции выполнились почти одновременно благодаря GIL
Примеры блокирующих операций:
socket.recv()— получение данных из сетиfile.read()— чтение файлаtime.sleep()— пауза в потокеsubprocess.call()— запуск процесса- Все операции с сетью (requests, urllib и т.д.)
3. При явном освобождении в C расширениях
Велики могут явно освобождать GIL в C коде через Py_BEGIN_ALLOW_THREADS и Py_END_ALLOW_THREADS:
// NumPy операции работают параллельно
// потому что освобождают GIL
import numpy as np
import threading
def matrix_mult(matrix):
# GIL отдан на время numpy операции!
return np.dot(matrix, matrix.T)
# Можно использовать потоки для параллельных вычислений
Проблема: CPU-bound операции
Для вычислительно интенсивных операций GIL НЕ отдаётся:
import threading
import time
def cpu_intensive():
total = 0
for i in range(100_000_000):
total += i
return total
# Способ 1: Threading (ПЛОХО для CPU-bound)
start = time.time()
t1 = threading.Thread(target=cpu_intensive)
t2 = threading.Thread(target=cpu_intensive)
t1.start()
t2.start()
t1.join()
t2.join()
thread_time = time.time() - start
print(f"Threading: {thread_time}s") # ~2s (один поток выполняет)
# Способ 2: Multiprocessing (ХОРОШО для CPU-bound)
from multiprocessing import Process
start = time.time()
p1 = Process(target=cpu_intensive)
p2 = Process(target=cpu_intensive)
p1.start()
p2.start()
p1.join()
p2.join()
process_time = time.time() - start
print(f"Multiprocessing: {process_time}s") # ~1s (реально параллельно)
Python 3.13+ — устранение GIL
В Python 3.13 начал вводиться режим без GIL (когда включён флаг --disable-gil):
python3.13 --disable-gil my_script.py
Это позволяет потокам работать по-настоящему параллельно.
Резюме: Когда GIL отдаёт управление
| Ситуация | GIL отдан? | Пример |
|---|---|---|
| I/O операция | ✅ ДА | requests.get(), socket.recv() |
time.sleep() | ✅ ДА | Пауза между запросами |
| Чтение/запись файлов | ✅ ДА | file.read(), file.write() |
| CPU-bound вычисления | ❌ НЕТ | Циклы, обработка данных |
| NumPy/SciPy операции | ✅ ДА | np.dot(), scipy.optimize |
Практические рекомендации
Для I/O-bound задач:
import asyncio
# Асинхронность лучше для I/O
async def fetch_many():
tasks = [asyncio.sleep(1) for _ in range(100)]
await asyncio.gather(*tasks)
Для CPU-bound задач:
from concurrent.futures import ProcessPoolExecutor
# Multiprocessing обходит GIL
with ProcessPoolExecutor(max_workers=4) as executor:
results = list(executor.map(cpu_intensive, range(4)))
ГIL отдаётся автоматически при I/O и принудительно через интервалы времени, но не помогает при вычислениях.