This commit is contained in:
lovinervy committed 2026-10-07 13:06:47 +05:00
commit c394677d07
59 files changed
+5149

No files matched your search

+115
View File
@@ -0,0 +1,115 @@
# Лабораторная работа 1. Последовательное вычисление и профилирование
**Время на работу:** 2 пары.
## Цель работы
Создать базовую линию: последовательную реализацию своей задачи и её замеры.
Без неё невозможно показать ускорение в следующих лабораторных — нечего будет
ускорять.
## Теория
### Последовательное вычисление
Программа выполняет операцию за операцией, в одном потоке управления. Это
простейшая и самая предсказуемая модель: результат не зависит от порядка
выполнения, время выполнения = сумма времён всех операций. Все дальнейшие
лабораторные сравниваются с этой базой.
### Два типа нагрузки
**CPU-bound** — программа ограничена скоростью процессора: считает, шифрует,
сортирует. Время определяется числом элементарных операций.
**I/O-bound** — программа ограничена ожиданием: сеть, диск, база данных.
Время определяется временем ожидания ответов, процессор при этом простаивает.
Отличить просто: если удалить «полезную работу», а программа всё равно
медленная — это I/O-bound; если быстрая — CPU-bound. Тип нагрузки определяет,
какая модель параллелизма поможет (потоки — для I/O, процессы — для CPU,
async — для I/O в больших количествах).
### Время: настенное и процессорное
- `time.perf_counter()` — «настенные» часы: сколько времени прошло реально
(включая сон и ожидание). Ими меряют всё в этом курсе.
- `time.process_time()` — только время, потраченное процессором.
Разница между ними для I/O-задачи огромна — это её диагноз.
Обе функции монотонные (не откатываются назад, как `time.time()` при
переводе часов), имеют наносекундное разрешение — всегда используйте их, а не
`time.time()`.
### Профилирование
Профилировщик отвечает на вопрос «где программа проводит время». `cProfile`
собирает статистику по функциям: число вызовов, суммарное время, время без
вложенных вызовов.
```python
import cProfile
cProfile.run("main()", sort="cumulative")
```
Интерпретация: колонка `cumtime` — общее время функции (с вызовами),
`totime` — собственное. Первые строки обычно сразу показывают узкое место.
## Задание
Ваша задача и параметры — по варианту (`common/варианты.md`), доступ:
```python
from common.tasks import get_variant, TASKS
v = get_variant(13) # ваш номер
task = TASKS[v["task_name"]]
data = task["build"](v["cpu_params"])
```
Заполните `solution.py` (интерфейсы менять нельзя):
1. **`run_cpu_sequential(task_name, params, parts=4)`** — выполняет задачу
последовательно: `build` → разбиение на `parts` кусков → `kernel` для
каждого куска в цикле → `combine` → вернуть `checksum`. Куски
обязательны: в следующих лабораторных те же куски уйдут воркерам.
2. **`run_io_sequential(items, delay)`** — для каждого элемента вызывает
`common.tasks.io_fetch(item, delay)` и собирает результаты в список
(в порядке возрастания item).
3. **`main()`** — запускает обе части на параметрах своего варианта, выводит
таблицу времен (`common.benchmark.make_table`) и значения checksum.
### Измерения для отчёта
- CPU-часть: T(1) при разбиении на 1, 2, 4 куска (убедитесь, что checksum
одинаков и время почти не меняется — разбиение не должно менять работу).
- I/O-часть: суммарное время для items из варианта; сравните
`perf_counter` и `process_time` — увидите, сколько времени машина спит.
- Профилирование CPU-части: `cProfile.run(...)`, топ-5 функций по времени.
Укажите в отчёте, какая функция — узкое место.
## Контрольные вопросы
1. Чем CPU-bound задача отличается от I/O-bound? Какая у вас?
2. Почему для замеров нужен `perf_counter`, а не `time.time()`?
3. Что показывает `cumtime` и `tototime` в выводе cProfile?
4. Почему checksum не должен зависеть от числа кусков? Что это проверяет?
## Что сдаётся
`solution.py` + отчёт по шаблону: таблицы T(1/2/4 кусков), время I/O-части,
сравнение perf_counter/process_time, топ-5 из cProfile, анализ.
## Критерии оценки
| Пункт | Баллы |
|---|---|
| `run_cpu_sequential` работает, checksum совпадает при разном разбиении | 2 |
| `run_io_sequential` работает | 1 |
| Замеры и сравнение perf_counter/process_time | 2 |
| Профилирование и вывод об узком месте | 2 |
| Отчёт: таблицы, анализ, ответы на вопросы | 3 |
## Типичные ошибки
См. `common/типичные_ошибки.md` (пп. 8, 9). Здесь их всего две: замеры в
отладчике и замеры без повторов.