Сравните модели параллельного программирования: shared‑memory (OpenMP, pthreads), message‑passing (MPI), data‑parallel (MapReduce, Spark) — для каких задач и архитектур каждая удобна, какие проблемы (synchronization, deadlock, load balancing, network overhead) наиболее критичны
Shared‑memory (OpenMP, pthreads) - Когда удобно: одноузловые многоядерные системы (SMP/NUMA), быстрые тонкозернистые параллельные участки, приложения с частым обменом маленькими данными (плотные линейные алгебраические ядра, компактные потоковые алгоритмы). - Плюсы: простота доступа к общей памяти, низкая задержка коммуникации между потоками, удобны для fine‑grained параллелизма и динамических задач внутри узла. - Основные проблемы (в порядке критичности): синхронизация (locks, atomic, barriers) — высокая стоимость при высокой частоте; ложное совместное использование кэша (false sharing) и конфликт кэшей; проблемы с согласованностью памяти на NUMA (производительность зависит от локальности); deadlock и livelock при неправильной блокировке — реальная угроза при ручных mutex; балансировка нагрузки решается потоковыми пуллами и work‑stealing, но масштаб ограничен пропускной способностью памяти. Сетевой overhead минимален (локальная память). Message‑passing (MPI) - Когда удобно: распределённые системы и кластеры с распределённой памятью, массово параллельные численные симуляции, масштабируемые HPC‑задачи, когда нужна явная коммуникация (стенцилы, линейные решатели). - Плюсы: хорошая масштабируемость на большое число узлов, явный контроль над коммуникацией и локальностью данных, оптимизации под сети (RDMA, неблокирующие операции). - Основные проблемы (в порядке критичности): сетевая нагрузка — задержка и пропускная способность (latency/bandwidth) критичны; синхронизация через collectives/барьеры — дорого при больших масштабах; deadlock при несогласованных send/recv или блокирующих операциях — частая ошибка; балансировка нагрузки (разбиение домена, динамическая миграция) критична для эффективного использования всех процессов; накладные расходы на сериализацию/копирование при больших сообщениях. Data‑parallel (MapReduce, Spark) - Когда удобно: обработка больших данных на кластерах/облаке, пакетная аналитика, ETL, распределённое обучение и графовые итеративные алгоритмы (в Spark) — задачи с высокой референтной локальностью по данным и удобной операцией «map/shuffle/reduce». - Плюсы: простая модель программирования высокого уровня, автоматическое управление задачами, встроенная устойчивость к сбоям, удобна для coarse‑grained параллелизма и ленивых DAG‑вычислений. - Основные проблемы (в порядке критичности): сетевой overhead при shuffle — главный узкий горлышко; страгглеры и ски́в данных (data skew) приводят к сильному дисбалансу; синхронизация на уровне этапов (barriers между стадиями) — грубая, но простая; deadlock редок (контролируется системой), но возможны проблемы из‑за блокирующих внешних зависимостей; управление памятью/GC и диск‑IO (spill) критично для производительности; балансировка достигается через партиционирование и динамическое распределение задач, но требует тюнинга. Краткие руководства по выбору - Нужен быстрый тонкий параллелизм внутри узла — shared‑memory (OpenMP/pthreads). - Нужна масштабируемость на кластере с минимальным обменом и максимальным контролем — MPI. - Обработка больших наборов данных с готовностью пожертвовать гибкостью ради простоты и отказоустойчивости — MapReduce/Spark. Короткие приёмы уменьшения проблем - Shared‑memory: минимизировать критические секции, использовать атомарные операции/lock‑free, оптимизировать доступ по NUMA, устранить false sharing. - MPI: использовать неблокирующие коммуникации, перекрывать коммуникацию и вычисления, оптимизировать топологию/разбиение, применять collective‑оптимизации. - Data‑parallel: улучшать партиционирование (pre‑shuffle), комбинировать локальные агрегаты (combiners), балансировать партиции, кэшировать горячие данные, оптимизировать shuffle и GC.
- Когда удобно: одноузловые многоядерные системы (SMP/NUMA), быстрые тонкозернистые параллельные участки, приложения с частым обменом маленькими данными (плотные линейные алгебраические ядра, компактные потоковые алгоритмы).
- Плюсы: простота доступа к общей памяти, низкая задержка коммуникации между потоками, удобны для fine‑grained параллелизма и динамических задач внутри узла.
- Основные проблемы (в порядке критичности): синхронизация (locks, atomic, barriers) — высокая стоимость при высокой частоте; ложное совместное использование кэша (false sharing) и конфликт кэшей; проблемы с согласованностью памяти на NUMA (производительность зависит от локальности); deadlock и livelock при неправильной блокировке — реальная угроза при ручных mutex; балансировка нагрузки решается потоковыми пуллами и work‑stealing, но масштаб ограничен пропускной способностью памяти. Сетевой overhead минимален (локальная память).
Message‑passing (MPI)
- Когда удобно: распределённые системы и кластеры с распределённой памятью, массово параллельные численные симуляции, масштабируемые HPC‑задачи, когда нужна явная коммуникация (стенцилы, линейные решатели).
- Плюсы: хорошая масштабируемость на большое число узлов, явный контроль над коммуникацией и локальностью данных, оптимизации под сети (RDMA, неблокирующие операции).
- Основные проблемы (в порядке критичности): сетевая нагрузка — задержка и пропускная способность (latency/bandwidth) критичны; синхронизация через collectives/барьеры — дорого при больших масштабах; deadlock при несогласованных send/recv или блокирующих операциях — частая ошибка; балансировка нагрузки (разбиение домена, динамическая миграция) критична для эффективного использования всех процессов; накладные расходы на сериализацию/копирование при больших сообщениях.
Data‑parallel (MapReduce, Spark)
- Когда удобно: обработка больших данных на кластерах/облаке, пакетная аналитика, ETL, распределённое обучение и графовые итеративные алгоритмы (в Spark) — задачи с высокой референтной локальностью по данным и удобной операцией «map/shuffle/reduce».
- Плюсы: простая модель программирования высокого уровня, автоматическое управление задачами, встроенная устойчивость к сбоям, удобна для coarse‑grained параллелизма и ленивых DAG‑вычислений.
- Основные проблемы (в порядке критичности): сетевой overhead при shuffle — главный узкий горлышко; страгглеры и ски́в данных (data skew) приводят к сильному дисбалансу; синхронизация на уровне этапов (barriers между стадиями) — грубая, но простая; deadlock редок (контролируется системой), но возможны проблемы из‑за блокирующих внешних зависимостей; управление памятью/GC и диск‑IO (spill) критично для производительности; балансировка достигается через партиционирование и динамическое распределение задач, но требует тюнинга.
Краткие руководства по выбору
- Нужен быстрый тонкий параллелизм внутри узла — shared‑memory (OpenMP/pthreads).
- Нужна масштабируемость на кластере с минимальным обменом и максимальным контролем — MPI.
- Обработка больших наборов данных с готовностью пожертвовать гибкостью ради простоты и отказоустойчивости — MapReduce/Spark.
Короткие приёмы уменьшения проблем
- Shared‑memory: минимизировать критические секции, использовать атомарные операции/lock‑free, оптимизировать доступ по NUMA, устранить false sharing.
- MPI: использовать неблокирующие коммуникации, перекрывать коммуникацию и вычисления, оптимизировать топологию/разбиение, применять collective‑оптимизации.
- Data‑parallel: улучшать партиционирование (pre‑shuffle), комбинировать локальные агрегаты (combiners), балансировать партиции, кэшировать горячие данные, оптимизировать shuffle и GC.