# -*- coding: utf-8 -*- """Лабораторная работа 1: последовательное вычисление и профилирование. Заполните функции ниже. ИНТЕРФЕЙСЫ МЕНЯТЬ НЕЛЬЗЯ — по ним работают автотесты (tests/test_lab01.py). Запуск из корня курса: python lab01_sequential/solution.py """ import os import sys import time sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from common.benchmark import make_table, time_call from common.tasks import TASKS, get_variant, io_fetch # TODO: впишите свой номер в журнале (1..20) VARIANT_NUMBER = 0 def run_cpu_sequential(task_name: str, params: dict, parts: int = 4): """Последовательное выполнение задачи из `parts` кусков. Возвращает (checksum, elapsed_seconds). Схема: build -> split -> kernel (по очереди!) -> combine -> checksum """ task = TASKS[task_name] # TODO: реализуйте по схеме выше и замерьте время perf_counter-ом raise NotImplementedError def run_io_sequential(items: int, delay: float = 0.05): """Последовательное выполнение I/O-нагрузки. Для каждого item из range(items) вызывает io_fetch(item, delay). Возвращает (список_результатов, elapsed_seconds). Результаты — в порядке возрастания item. """ # TODO: цикл по items, сбор результатов, замер времени raise NotImplementedError def main(): v = get_variant(VARIANT_NUMBER) print(f"Вариант {v['variant']}: {v['describe']}") print(f"I/O-нагрузка: {v['io']['items']} запросов по {v['io']['delay']} c\n") # --- CPU-часть: T(1), T(2), T(4) -------------------------------------- rows, checksums = [], [] for parts in (1, 2, 4): t, (cs, _) = time_call(run_cpu_sequential, (v["task_name"], v["cpu_params"], parts)) rows.append((f"CPU, {parts} кусков", t)) checksums.append(cs) print(make_table(rows, title="CPU-часть (последовательно)")) def same(a, b): # float-результаты сравниваем с допуском (порядок суммирования!) if isinstance(a, float) or isinstance(b, float): return abs(a - b) <= 1e-6 * max(1.0, abs(a)) return a == b ok = all(same(checksums[0], c) for c in checksums[1:]) print(f"checksum совпадает при разном разбиении: {ok}\n") # --- I/O-часть ---------------------------------------------------------- results, t_io = run_io_sequential(v["io"]["items"], v["io"]["delay"]) t0 = time.perf_counter() c0 = time.process_time() run_io_sequential(v["io"]["items"], v["io"]["delay"]) wall = time.perf_counter() - t0 proc = time.process_time() - c0 print(f"I/O-часть: {len(results)} запросов за {t_io:.3f} c") print(f" настенное время (perf_counter): {wall:.3f} c") print(f" процессорное время (process_time): {proc:.3f} c") print(f" доля ожидания: {100 * (1 - proc / wall):.0f}%") print(f" потенциал ускорения потоками (лаба 2): x{t_io / v['io']['delay']:.1f}\n") # --- Профилирование ------------------------------------------------------ import cProfile import io as _io import pstats print("--- cProfile CPU-части (топ-5 по времени) ---") profiler = cProfile.Profile() profiler.enable() run_cpu_sequential(v["task_name"], v["cpu_params"], parts=4) profiler.disable() stream = _io.StringIO() pstats.Stats(profiler, stream=stream).sort_stats("cumulative").print_stats(5) print(stream.getvalue()) # TODO: выпишите в отчёт, какая функция — узкое место if __name__ == "__main__": main()