76 lines
2.7 KiB
Python
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() |