Files
parallel-programming/lab03_gil/examples/01_gil_basics_demo.py
T
2026-10-07 13:06:47 +05:00

76 lines
2.7 KiB
Python

# -*- coding: utf-8 -*-
"""Демо: GIL изнутри — интервал переключения и stat.
Запуск из корня курса:
python lab03_gil/examples/01_gil_basics_demo.py
Показывает:
- sys.getswitchinterval() — как часто потоки уступают GIL;
- sys._is_gil_enabled() (Python 3.13+) — статус GIL;
- поток-«наблюдатель» работает, пока главный поток занят счётом
(переключения есть!), но суммарная производительность не растёт.
"""
import os
import sys
import threading
import time
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
def burn(n):
s = 0.0
for i in range(n):
s += i ** 0.5
return s
def main():
print(f"Python: {sys.version.split()[0]}")
if hasattr(sys, "_is_gil_enabled"):
print(f"GIL включён: {sys._is_gil_enabled()}")
print(f"интервал переключения GIL: {sys.getswitchinterval() * 1000:.0f} мс\n")
N = 4_000_000
# 1. Один поток
t0 = time.perf_counter()
burn(N)
t1 = time.perf_counter() - t0
print(f"1 поток: {t1:.3f} c")
# 2. Поток-наблюдатель: он живёт (переключения идут), но работе это не помогает
ticks = [0]
def observer(stop_flag):
while not stop_flag[0]:
ticks[0] += 1
time.sleep(0.005)
stop = [False]
obs = threading.Thread(target=observer, args=(stop,), daemon=True)
obs.start()
t0 = time.perf_counter()
burn(N) # главный поток считает
t2 = time.perf_counter() - t0
stop[0] = True
obs.join()
print(f"1 поток + наблюдатель: {t2:.3f} c (наблюдатель проснулся "
f"{ticks[0]} раз) — работа не замедлилась: переключения дешёвые")
# 3. Два считающих потока: время то же, работы вдвое больше — но не быстрее
t0 = time.perf_counter()
threads = [threading.Thread(target=burn, args=(N // 2,)) for _ in range(2)]
for t in threads:
t.start()
for t in threads:
t.join()
t4 = time.perf_counter() - t0
print(f"2 потока по {N // 2}: {t4:.3f} c => S={t1 / t4:.2f} (GIL!)")
print("\nВывод: переключения GIL происходят, но байт-код всё равно")
print("исполняется по очереди — суммарная скорость не растёт.")
if __name__ == "__main__":
main()