6.1 KiB
Лабораторная работа 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-сценарий (задача из варианта):
cpu_sequential(task_name, params)— как в лабе 1;cpu_threads(task_name, params, p)— как в лабе 3 (S ≈ 1!);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 так, чтобы теория совпала с практикой) — укажите его в отчёте.
Контрольные вопросы
- Почему потоки не ускорили CPU-задачу, но ускорили I/O?
- Почему asyncio на I/O обгоняет потоки? Откуда выигрыш?
- Какая доля последовательного кода получилась у процессов по Амдалу? Что в неё входит?
- Какую модель вы выбрали бы для веб-краулера на 10 000 страниц? Для рендера видео? Обоснуйте.
- Что в ваших замерах не совпало с теорией и почему?
Что сдаётся
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).