2008-11-01 5 views
8

Недавно я писал много о параллельных вычислениях и программировании, и я замечаю, что существует много шаблонов, которые возникают, когда речь идет о параллельных вычислениях. Отметив, что Microsoft уже выпустила библиотеку вместе с Техническим предварительным просмотром сообщества Microsoft Visual C++ 2010 (так называемая библиотека параллельных шаблонов), мне интересно, какие общие шаблоны параллельного программирования вы используете и сталкиваетесь, что может быть интересно запомнить? У вас есть какие-либо идиомы, которые вы следуете, и шаблоны, которые, по-видимому, появляются, когда вы пишете параллельные программы с C++?Параллельное программирование и C++

+0

Можете ли вы уточнить, какое именно параллельное программирование вам интересны? Распределенное программирование с использованием MPI значительно отличается от параллелизма уровня цикла с использованием OpenMP. – mch 2008-11-01 17:58:17

+0

Меня особенно интересуют общие шаблоны и идиомы в параллельном программировании - будь то с распределенной памятью или моделями с общей памятью на одной машине или на нескольких машинах. – 2008-11-01 18:09:35

ответ

17

Patterns:

  • Produce/Потребительские

    • One Thread производит данные
    • One Thread потребляет данные
  • петля Параллелизм

    • Если вы можете показать, что каждый цикл не зависит
      каждой итерации может быть сделано в Sperate нити
  • перерисовать темы

    • Другие нити делают работы и обновления данных структур, но один thread re-draws screen.
  • Main-Event темы

    • Несколько потоков могут генерировать события
    • Один поток должен обрабатывает события (как порядок важен)
    • Если попытаться отделить событие Тема/Re -Draw Thread
      Это (помогает) предотвращает зависание пользовательского интерфейса
      Но может привести к чрезмерному повторному розыгрышу, если это не сделано тщательно.
  • Рабочая группа

    • Набор нитей ждет рабочих мест на дие.
    • Извлечь из рабочей очереди один рабочий элемент из очереди (ожидающий, если он недоступен).
      Нить работает на одном рабочем месте до завершения
      После завершения потока возвращается в очередь.
+0

Отличный список, спасибо! – 2008-11-01 18:42:00

2

Прежде всего вам нужно выбирать между компьютерами с общей памятью и вычислениями общего пользования. Общая память проще, но не масштабируется, что хорошо - вы будете использовать совместно-ничего, если вы либо

а) имеют кластер, а не многопроцессорной системы, или

б) если у вас есть много процессоров (скажем,> 60) и высокой степени неоднородной памяти

Для общей памяти общим решением является использование потоков; их легко понять как концепцию и прост в использовании в API (но трудно отлаживать).

Для совместного использования ничего не используется, вы используете какой-то обмен сообщениями. В высокопроизводительных вычислениях MPI устанавливается как промежуточное программное обеспечение для обмена сообщениями.

Вам также необходимо спроектировать архитектуру для параллельных действий. Наиболее распространенный подход (опять же потому, что это легко понять) - это образец фермера-работника (a.k.a. master-slave).

+0

Чтобы быть справедливым, вам не обязательно выбирать только одно - вы можете создать архитектуру, которая поддерживает оба. Но эти моменты действительны - вам нужно четко понимать, что вы поддерживаете там, потому что требования (и часто проекты) совершенно разные. – 2008-11-25 15:59:16

2

параллельного выполнения Шаблоны

Структурированная параллельное программирование с детерминированных моделей является подход на высоком уровне, главным образом, на основе сбора периодических параллельных моделей исполнения, часто упоминается как алгоритмические скелеты или параллельных конструкций , которое описывает абстрактное описание программы и скрывает детали многопоточности низкого уровня и множество сложностей, присущих параллелизму со стороны программистов.

Эти шаблоны многократного использования автоматизируют многие параллельные парадигмы, такие как синхронизация, связь, разделение данных или планирование задач и их внутренняя обработка. Этот подход высокого уровня пытается использовать традиционную низкоуровневую систему блокировки потоков с большей абстракцией и более простой способ выразить параллельность и повысить производительность и программируемость, а не производительность.

Там же многие часто используемые шаблоны, такие как: Map-Reduce, Fork-Join, трубопроводы или параллельный цикл ...

Papers

"Структурированное Параллельное программирование с детерминированной Patterns" является бумагой, которая обсудите эти закономерности. Вы также можете увидеть «MHPM: многомасштабная модель гибридного программирования: гибкая методология параллелизации», в которой описывается реализация этого подхода под названием XPU.

Библиотека

XPU является ++ библиотека задач на основе C состоит из набора повторно используемых моделей исполнения. Это позволяет выражать несколько типов параллелизма на нескольких уровнях детализации внутри одной однородной модели программирования. Он прост в использовании и иллюстрирует стремление использовать шаблоны для разработки параллельных программ.

Например, это позволяет выражение:

  1. параллелизм задач Шаблон:

    Простой или Иерархическая Fork/Join шаблон выполнения с некоторыми функциями, такими, как автоматического обнаружения и защиты общих данных.

  2. параллелизм данных Шаблон:

    Параллельный цикл модели с масштабируемым разделения данных.

  3. Temporal параллелизм Выкройка:

    Pipeline модель выполнения.

0

У вас есть основы, которые запирают параллелизм частям программы. C++ 17 получает много из них (например, параллельные версии foreach, sort, find и friends, map_reduce, map, reduce, prefix_sum ...) см. C++ Extensions for Parallelism

Тогда у вас есть такие предметы, как продолжения. Подумайте, std::future, но с продолжением. Существует несколько способов их реализации (boost имеет хороший вариант, так как std не имеет следующего (...) или затем (...) метода, но большая выгода заключается в том, что не нужно ждать это сделать следующую задачу

auto fut = async([](){..some work...}).then([](result_of_prev){...more work}).then... ; 
fut.wait(); 

отсутствие синхронизации между последующими задачами важно, так как связи между задачами/нитями/... это то, что замедляет параллельные программы.

так что с этой задачей на основе параллельности очень хорошо. С планировщиком задач вы просто передаете задания и уходите. У них могут быть методы, например семафор, для связи, но это необязательно. Оба Intel Thread Building Blocks и Microsoft Parallel Pattern Library имеют fa для этого.

После этого у нас есть модель fork/join. Это не подразумевает создание N потоков для каждой задачи. Просто у вас есть эти N, идеально независимые вещи, которые нужно делать (fork), и когда они сделаны, есть точка синхронизации где-нибудь (join).

auto semaphore = make_semaphore(num_tasks); 
add_task([&semaphore]() {...task1...; semaphore.notify(); }); 
add_task([&semaphore]() {...task2...; semaphore.notify(); }); 
... 
add_task([&semaphore]() {...taskN...; semaphore.notify(); }); 
semaphore.wait(); 

Сверху вы можете начать просмотр шаблона, который является потоковым графом. Будущее (A >> B >> C >> D) и Fork Join (A | B | C | D). С этим вы можете объединить их для формирования графика. (A1 >> A2 | B1 >> B2 >> B3 | C1 | D1 >> D2 >> (E1 >> E2 | F1)), где A1 >> A2 означает, что A1 должен предшествовать A2, а A | B означает, что A и B может работать одновременно. Медленные части находятся в конце графиков/подграфов, где встречаются вещи.

Цель состоит в том, чтобы найти независимые части системы, которые не нуждаются в общении. Параллельные алгоритмы, как отмечалось выше, почти во всех случаях медленнее, чем их последовательные копии, пока рабочая нагрузка не станет достаточно высокой или размер становится достаточно большим (при условии, что общение не слишком чатовое). Например, сортировка. На четырехъядерном компьютере вы получите около 2,5X производительности, которые дают или принимают, потому что слияние является частым и требует много синхронизации и не работает со всеми ядрами после первого раунда слияния. На графическом процессоре с N, который является очень большим, можно использовать менее эффективную сортировку, такую ​​как Bitonic, и она заканчивается очень быстро, потому что у вас много рабочих, чтобы работать через работу, и все спокойно делают свое дело.

Некоторые трюки для уменьшения связи включают в себя, используя массив для получения результатов, чтобы каждая задача не пыталась заблокировать объект, чтобы подтолкнуть значение. Часто позже сокращение этих результатов может быть очень быстрым.

Но со всеми типами параллелизма медлительность происходит от общения. Уменьшите его.

Смежные вопросы