Статьи
September 6

GIL станет необязательным в Python 3.13

GIL (он же Global Interpreter Lock) может быть отключен в Python версии 3.13. Пока эта возможность является экспериментальной.

Кто такой этот GIL? Это механизм, используемый интерпретатором CPython для обеспечения выполнения байткода Python одновременно только одним потоком.

Экспериментальная функция

В Python 3.13 среди прочих нововведений привнесёт режим свободных потоков, который отключает глобальную блокировку интерпретатора, позволяя потокам работать параллельно.

Это экспериментальная функция, и если вы хотите попробовать ее, вы можете скачать бета-версию Python 3.13 здесь. А во время установки отметьте опцию «free threaded binaries(experimental)».

Отключение GIL в Python 3.13

GIL будет отключен, если сконфигурировать Python с параметром --disable-gil. Это позволит опционально включать и отключать GIL с помощью переменной окружения PYTHON_GIL, которая может быть установлена в значения 1 и 0 соответственно.

Также будет доступна опция командной строки -X gil, которая может быть установлена в 0 (отключен) и 1 (включен).

# v3.13
# GI отключен
python3 -X gil=0 sample.py
 
# GIL включен
python3 -X gil=1 sample.py

Проверить, активированы ли в текущем интерпретаторе свободные потоки (--disable-gil) можно так:

import sysconfig
print(sysconfig.get_config_var("Py_GIL_DISABLED"))

Мы получим либо 0 (GIL включен), либо 1 (GIL отключен).

GIL Vs No GIL

Давайте посмотрим, как повлияет на производительность многопоточных программ включение и отключение GIL.

Есть простой скрипт (gil.py), который вычисляет факториал числа и сравнивает время выполнения в однопоточном, многопоточном и многопроцессорном режимах. Запустим этот скрипт сначала с GIL, а затем без GIL.

import sys
import sysconfig
import math
import time
import threading
import multiprocessing
 
def compute_factorial(n):
    return math.factorial(n)
 
# Однопоточное исполнение
def single_threaded_compute(n):
    for num in n:
        compute_factorial(num)
    print("Факториал вычислен в один поток.")
 
# Многопоточное исполннение
def multi_threaded_compute(n):
    threads = []
    # Создаем 5 потоков
    for num in n:
        thread = threading.Thread(target=compute_factorial, args=(num,))
        threads.append(thread)
        thread.start()
 
    # Ждём исполнения всех потоков
    for thread in threads:
        thread.join()
 
    print("Факториал вычислен в 5 потоков")
 
# Мультипроцессорное исполнение
def multi_processing_compute(n):
    processes = []
    # Создаём процесс для каждого числа
    for num in n:
        process = multiprocessing.Process(target=compute_factorial, args=(num,))
        processes.append(process)
        process.start()
 
    # Ожидаем исполнение всех процессов
    for process in processes:
        process.join()
 
    print("Факториал вычислен в мультипроцессорном режиме.")
 
def main():
    # Проверяем версию
    print(f"Версия Python: {sys.version}")
 
    # GIL Status
    status = sysconfig.get_config_var("Py_GIL_DISABLED")
    if status is None:
        print("GIL не может быть отключен")
    if status == 0:
        print("GIL включен")
    if status == 1:
        print("GIL отключен")
 
    numlist = [100000, 200000, 300000, 400000, 500000]
 
    # Однопоточное исполнение
    start = time.time()
    single_threaded_compute(numlist)
    end = time.time() - start
    print(f"Время исполнения в один поток: {end:.2f} секунд")
 
    # Многопоточное исполнение
    start = time.time()
    multi_threaded_compute(numlist)
    end = time.time() - start
    print(f"Многопоточное время исполнения: {end:.2f} секунд")
 
    # Мультипроцессорное исполнение
    start = time.time()
    multi_processing_compute(numlist)
    end = time.time() - start
    print(f"Мультипроцессорное время исполнения: {end:.2f} секунд")
 
 
if __name__ == "__main__":
    main()

Running gil.py with GIL

Версия Python: 3.13.0b3 experimental free-threading build (tags/v3.13.0b3:7b41395, Jun 27 2024, 16:17:17) [MSC v.1940 64 bit (AMD64)]
GIL отключен
Факториал вычислен в один поток.
Время исполнения в один поток: 9.28 секунд
Факториал вычислен в 5 потоков
Многопоточное время исполнения: 4.86 секунд
Факториал вычислен в мультипроцессорном режиме.
Мультипроцессорное время исполнения: 6.14 секунд

Здесь у нас третья бета-версия Python 3.13 с активированными свободными потоками, и, как мы видим, GIL отключен.

Но самое главное - мы видим значительную разницу в производительности в многопоточных задачах, но при этом можно заметить некоторое снижение скорости в многопроцессорных и однопоточных задачах.

👉🏻Подписывайтесь на PythonTalk в Telegram 👈🏻

👨🏻‍💻Чат PythonTalk в Telegram💬

🍩 Поддержать канал 🫶

Источник: GeekPython