Init
This commit is contained in:
commit
c394677d07
59 files changed
+5149
No files matched your search
@@ -0,0 +1,116 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Лабораторная работа 3: GIL — почему потоки не ускоряют CPU-код.
|
||||
|
||||
Заполните функции ниже. ИНТЕРФЕЙСЫ МЕНЯТЬ НЕЛЬЗЯ — по ним работают
|
||||
автотесты (tests/test_lab03.py).
|
||||
|
||||
Запуск из корня курса:
|
||||
python lab03_gil/solution.py
|
||||
"""
|
||||
import hashlib
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
from common.benchmark import save_speedup_plot, time_call
|
||||
from common.tasks import TASKS, get_variant
|
||||
|
||||
# TODO: впишите свой номер в журнале (1..20)
|
||||
VARIANT_NUMBER = 0
|
||||
|
||||
|
||||
def run_task_on_threads(task_name: str, params: dict, p: int):
|
||||
"""Выполнить CPU-задачу на p потоках (ThreadPoolExecutor).
|
||||
|
||||
Каждый поток получает свой кусок (task['split']) и выполняет task['kernel'].
|
||||
Вернуть (checksum, elapsed_seconds). checksum обязан совпасть с
|
||||
последовательным запуском — иначе разбиение/сборка неверны.
|
||||
|
||||
Подсказка: потоки, в отличие от процессов, не требуют пиккелируемости —
|
||||
task["kernel"] можно вызывать прямо в воркере.
|
||||
"""
|
||||
task = TASKS[task_name]
|
||||
# TODO: build -> split -> pool.map(kernel, chunks) -> combine -> checksum
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def measure_cpu_threads(task_name: str, params: dict, p_list):
|
||||
"""Замеры T(p) на потоках для чистого-Python задачи.
|
||||
|
||||
Вернуть dict {p: лучшее_время}. p=1 — база. Проверять совпадение
|
||||
checksum при каждом p!
|
||||
"""
|
||||
# TODO: для каждого p -> time_call(run_task_on_threads, ..., repeats=3)
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def measure_gil_release(p_list, block_size=1 << 20, blocks_per_part=32):
|
||||
"""Замеры T(p) для hashlib (освобождает GIL на длинных вызовах).
|
||||
|
||||
Готовит данные заранее: W = blocks_per_part * max(p_list) блоков по
|
||||
block_size байт (os.urandom). Общий объём W делится между p потоками —
|
||||
как в CPU-замерах. Вернуть dict {p: лучшее_время}, checksum проверять.
|
||||
|
||||
ВАЖНО: блоки должны быть большими (≥ 256 КБ). На коротких вызовах GIL
|
||||
возвращается мгновенно и ускорение пропадает. Сравните block_size=4096
|
||||
и block_size=1<<20 в отчёте!
|
||||
"""
|
||||
# TODO: данные -> деление на p кусков -> ThreadPoolExecutor ->
|
||||
# hashlib.sha256(блок).digest() -> checksum -> {p: время}
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def gil_status():
|
||||
"""Вернуть (версия_python, gil_enabled: bool).
|
||||
|
||||
Используйте sys._is_gil_enabled() (Python 3.13+); если атрибута нет,
|
||||
считайте GIL включённым.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def main():
|
||||
v = get_variant(VARIANT_NUMBER)
|
||||
print(f"Вариант {v['variant']}: {v['describe']}\n")
|
||||
|
||||
ver, gil = gil_status()
|
||||
print(f"Python {ver}, GIL включён: {gil}\n")
|
||||
|
||||
# --- 1. Чистый Python: S(p) ≈ 1 ---------------------------------------
|
||||
t_cpu = measure_cpu_threads(v["task_name"], v["cpu_params"], v["p_list"])
|
||||
print("Чистый Python (GIL не отпускается):")
|
||||
base = t_cpu[1]
|
||||
for p, t in sorted(t_cpu.items()):
|
||||
print(f" p={p}: T={t:.3f} c S={base / t:.2f}")
|
||||
|
||||
# --- 2. hashlib: S(p) > 1 ---------------------------------------------
|
||||
t_hash = measure_gil_release(v["p_list"])
|
||||
print("\nhashlib SHA-256 (GIL отпускается, блоки 1 МБ):")
|
||||
base = t_hash[1]
|
||||
for p, t in sorted(t_hash.items()):
|
||||
print(f" p={p}: T={t:.3f} c S={base / t:.2f}")
|
||||
|
||||
# --- 2b. Мелкие блоки: ускорение должно исчезнуть ----------------------
|
||||
t_small = measure_gil_release(v["p_list"], block_size=4096,
|
||||
blocks_per_part=8000)
|
||||
print("\nhashlib SHA-256 (блоки 4 КБ — GIL возвращается сразу):")
|
||||
base = t_small[1]
|
||||
for p, t in sorted(t_small.items()):
|
||||
print(f" p={p}: T={t:.3f} c S={base / t:.2f}")
|
||||
|
||||
# --- 3. График ----------------------------------------------------------
|
||||
save_speedup_plot(
|
||||
{"чистый Python": sorted(t_cpu.items()),
|
||||
"hashlib 1 МБ (released GIL)": sorted(t_hash.items()),
|
||||
"hashlib 4 КБ": sorted(t_small.items())},
|
||||
f"GIL: ускорение потоками (Python {ver})",
|
||||
os.path.join(os.path.dirname(__file__), "speedup.png"))
|
||||
|
||||
# TODO: в отчёт — таблицу серий, график, объяснение разницы кривых,
|
||||
# ответы на контрольные вопросы из методички.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user