Учебник Параллельные алгоритмы для начинающих
Курс о том, как проектировать параллельные алгоритмы — раскладывать вычисление на много ядер, узлов кластера и тысячи потоков GPU ради скорости. Вы разберёте, почему остановился рост частоты процессоров, как измеряют ускорение, почему последовательная часть ограничивает выигрыш (закон Амдала) и как задача масштабируется с ресурсами (закон Густафсона). Освоите фундаментальные параллельные примитивы — map, редукцию деревом, префиксные суммы (scan), — параллельную сортировку и обходы графов, умножение матриц и модель fork-join с балансировкой work stealing. Познакомитесь с практическими моделями программирования (OpenMP, MPI, CUDA/SIMT, MapReduce/Spark), научитесь анализировать алгоритм через work и span и избегать типичных ошибок вроде false sharing. Это курс про дизайн параллельных вычислений, а не про синхронизацию потоков — для последней есть курс «Конкурентность и многопоточность».
Курс «Параллельные алгоритмы» состоит из 8 разделов и 28 уроков: Зачем и в каких моделях, Метрики и законы масштабирования, Декомпозиция работы, Параллельные примитивы, Сортировка, поиск и графы, Матрицы и разделяй-и-властвуй, Модели программирования и Паттерны, анализ и практика. Уроки идут по порядку — от основ к более сложным темам, в каждом есть объяснение с примерами, а в конце — вопросы для самопроверки. К урокам привязаны задачи с автоматической проверкой: прочитали тему — сразу закрепили её кодом.
Программа курса
1 Зачем и в каких моделях
- Зачем нужны параллельные алгоритмы
Почему рост частоты CPU остановился, а будущее производительности — за многоядерностью, GPU и масштабом данных.
- Конкурентность против параллелизма
Чёткое различие между конкурентностью (управление многими задачами) и параллелизмом (одновременное выполнение ради скорости).
- Модели параллельных вычислений: PRAM, память, SIMD/MIMD, BSP
Обзор теоретических и практических моделей: PRAM, разделяемая и распределённая память, SIMD/MIMD, модель BSP.
- Зачем нужны параллельные алгоритмы
2 Метрики и законы масштабирования
- Метрики: ускорение, эффективность, масштабируемость
Как измеряют успех параллельного алгоритма: speedup, эффективность, сильная и слабая масштабируемость.
- Закон Амдала: почему последовательная часть всё ограничивает
Ключевая идея параллелизма: непараллелимая доля задаёт жёсткий потолок ускорения. Расчёт на исполнимом Python.
- Закон Густафсона: масштабирование задачи
Оптимистичный взгляд: когда задача растёт вместе с числом процессоров, ускорение масштабируется почти линейно.
- Накладные расходы: почему 2 ядра не дают ровно 2x
Коммуникация, синхронизация, создание потоков и дисбаланс — невидимые налоги, съедающие ускорение.
- Метрики: ускорение, эффективность, масштабируемость
3 Декомпозиция работы
- Декомпозиция данных против декомпозиции задач
Два главных способа разрезать работу: по данным (одна операция на разные куски) и по задачам (разные операции).
- Гранулярность и баланс нагрузки
Как выбрать размер кусков работы и распределить их ровно, чтобы ядра не простаивали.
- Декомпозиция данных против декомпозиции задач
4 Параллельные примитивы
- Параллельные примитивы: map и reduce
Map и reduce — два кирпича, из которых складывается большинство параллельных алгоритмов.
- Параллельная редукция: дерево сложения за O(log n)
Как свернуть n чисел не за n-1 шагов, а за log n: схема дерева редукции с пошаговой эмуляцией.
- Параллельный scan: префиксные суммы (Hillis-Steele)
Префиксная сумма выглядит строго последовательной, но считается параллельно за log n шагов. Алгоритм Hillis-Steele.
- Work-efficient scan: алгоритм Blelloch
Экономный по работе scan за O(n) операций: фазы up-sweep и down-sweep по дереву.
- Параллельные примитивы: map и reduce
5 Сортировка, поиск и графы
- Битоническая сортировка: сортировочная сеть
Сеть из компараторов, сортирующая за фиксированное число шагов независимо от данных — идеал для GPU.
- Чётно-нечётная сортировка слиянием
Простая локальная сортировка для решёток процессоров: соседи обмениваются и упорядочиваются по фазам.
- Sample sort и почему quicksort плохо параллелится
Sample sort масштабируется на кластерах: разбить диапазон по сэмплам, разложить по корзинам, отсортировать локально.
- Параллельный поиск, BFS и связные компоненты
Поиск в массиве, обход графа в ширину по уровням и связные компоненты — что параллелится легко, а что трудно.
- Битоническая сортировка: сортировочная сеть
6 Матрицы и разделяй-и-властвуй
- Параллельное умножение матриц
Почему умножение матриц — образцовая параллельная задача: независимые элементы, блочное разбиение, отличная масштабируемость.
- Разделяй-и-властвуй параллельно: fork-join
Модель fork-join: рекурсивно делим задачу, считаем половины параллельно, объединяем. Основа Cilk, OpenMP tasks, Java ForkJoinPool.
- Work stealing: как планировщик балансирует ветви
Механизм, который сам выравнивает нагрузку fork-join: простаивающее ядро крадёт задачу из очереди занятого.
- Параллельное умножение матриц
7 Модели программирования
- Потоки и OpenMP: разделяемая память на директивах
OpenMP позволяет распараллелить циклы C/C++ парой директив #pragma — обзор модели разделяемой памяти.
- MPI: передача сообщений для кластеров
MPI — стандарт распределённой памяти: процессы на разных узлах обмениваются сообщениями. Обзор send/recv и коллективов.
- GPU и data-parallel: модель SIMT (CUDA)
Тысячи лёгких потоков выполняют одно ядро над разными данными. Когда GPU выигрывает, а когда нет.
- MapReduce и Spark: параллелизм на кластере
Модель MapReduce и Spark распределяют обработку больших данных по тысячам узлов, скрывая координацию от программиста.
- Потоки и OpenMP: разделяемая память на директивах
8 Паттерны, анализ и практика
- Паттерны: master-worker, pipeline, stencil
Три повторяющихся структуры параллельных программ: пул заданий, конвейер стадий и обновление по соседям.
- Анализ параллельных алгоритмов: work и span
Две меры алгоритма: общая работа и критический путь (span). Их отношение — потенциальный параллелизм.
- Типичные ошибки: false sharing, дисбаланс, лишняя синхронизация
Скрытые убийцы производительности: ложное разделение кэша, перекос нагрузки, чрезмерные блокировки, неверная гранулярность.
- Гонки в параллельных алгоритмах и когда НЕ стоит параллелить
Краткий разбор гонок данных и трезвый взгляд: задачи, где параллелизм не окупается или вредит.
- Паттерны: master-worker, pipeline, stencil