# -*- 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()