Files
parallel-programming/lab07_comparison/методичка.md
T
2026-10-07 13:06:47 +05:00

110 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Лабораторная работа 7. Сравнительный анализ: одна задача — четыре подхода
**Время на работу:** 2 пары. **Зависимости:** лабы 1–6. Итоговая работа.
## Цель работы
Свести весь курс в одну таблицу: ваша CPU-задача и ваша I/O-нагрузка,
выполненные последовательно, потоками, процессами и асинхронно. Объяснить
каждую цифру. Это работа для защиты: по ней проверяется понимание всего
курса.
## Теория
### Ускорение и эффективность
- Ускорение: **S(p) = T(1) / T(p)** — во сколько раз быстрее на p воркерах.
- Эффективность: **E(p) = S(p) / p** — насколько эффективно используется
каждый воркер. E = 1 — идеал, E = 0.5 — половина мощности простаивает.
### Закон Амдала
Если доля последовательного кода задачи равна s (0 ≤ s ≤ 1), то ускорение
ограничено:
```
S(p) ≤ 1 / (s + (1 − s) / p)
```
При s = 0.1 и p → ∞: S ≤ 10. Даже бесконечное число воркеров не даст
больше 10×. Отсюда главный вывод курса: **сначала сокращайте
последовательную часть и накладные расходы, потом наращивайте p.**
В `common.benchmark` есть `amdahl(s, p)` — сравните свои S(p) с теорией:
зная измеренное S(p), можно оценить эффективную долю последовательной части
вашего эксперимента (создание пулов, pickle, GIL-переключения — всё это
«последовательная» часть).
### Матрица выбора модели
| Задача | Потоки | Процессы | asyncio |
|---|---|---|---|
| CPU-bound (чистый Python) | ✗ (GIL) | ✓ | ✗ (блокирует loop) |
| CPU-bound в C-коде (hashlib, numpy) | ✓ | ✓ | ✗ |
| I/O-bound, десятки задач | ✓ | возможно (дорого) | ✓ |
| I/O-bound, тысячи задач | дорого | ✗ | ✓✓ |
## Задание
Заполните `solution.py` — оба сценария из ваших лабораторных:
**CPU-сценарий** (задача из варианта):
1. `cpu_sequential(task_name, params)` — как в лабе 1;
2. `cpu_threads(task_name, params, p)` — как в лабе 3 (S ≈ 1!);
3. `cpu_processes(task_name, params, p)` — как в лабе 4 (S ≈ ядра).
**I/O-сценарий** (items × delay из варианта):
4. `io_sequential(items, delay)` — как в лабе 1;
5. `io_threads(items, delay, p)` — как в лабе 2;
6. `io_async(items, delay)` — как в лабе 6;
7. `io_async_limited(items, delay, max_concurrent)` — с семафором 8.
**`main()`** — таблицы для обоих сценариев с T(p), S(p), E(p); два графика
ускорения; оценка доли s по закону Амдала для процессов.
### Ожидаемые результаты (сверьтесь)
CPU: потоки S ≈ 1; процессы S(p) ≈ до числа физических ядер.
I/O: последовательный — база; потоки и async — S ≈ p; async без лимита —
минимальное время (нет расходов на потоки); processes для I/O — работает,
но с заметными накладными расходами.
### Что дополнительно оценить
- Разница T(1) у процессов против последовательного — цена старта процессов
и pickle.
- По S(p_max) процессов найдите s через `amdahl` (подберите s так, чтобы
теория совпала с практикой) — укажите его в отчёте.
## Контрольные вопросы
1. Почему потоки не ускорили CPU-задачу, но ускорили I/O?
2. Почему asyncio на I/O обгоняет потоки? Откуда выигрыш?
3. Какая доля последовательного кода получилась у процессов по Амдалу?
Что в неё входит?
4. Какую модель вы выбрали бы для веб-краулера на 10 000 страниц?
Для рендера видео? Обоснуйте.
5. Что в ваших замерах не совпало с теорией и почему?
## Что сдаётся
`solution.py` + отчёт: две таблицы (CPU и I/O) с T/S/E, два графика,
оценка s по Амдалу, развёрнутые выводы (это итоговая работа — выводы
должны покрывать весь курс), ответы на вопросы.
## Критерии оценки
| Пункт | Баллы |
|---|---|
| Все 7 функций работают, checksum корректен | 3 |
| Таблицы и графики для обоих сценариев | 3 |
| Оценка s по закону Амдала с объяснением | 2 |
| Выводы и ответы на вопросы (защита) | 4 |
## Типичные ошибки
- Сравнение T(p) разных сценариев при разном объёме работы — объём
фиксирован внутри сценария.
- Забыт smoke-режим `LAB_SMOKE` (автотесты запускают solution.py
подпроцессом — не удаляйте блок в main()).
- Замеры в один запуск без повторов: `time_call(..., repeats=3)`.