NexxDigital - компьютеры и операционные системы

В этой заметке показано как установить MPI, подключить его к Visual Studio, а затем использовать с заданными параметрами (числом вычислительных узлов). В статье используется Visual Studio 2015, т.к. именно с ней возникали проблемы у моих студентов (эта заметка написана студентами для студентов), однако вероятно инструкция подойдет и для других версий.

Шаг 1:
Необходимо установить пакет HPC Pack 2008 SDK SP2 (в вашем случае может быть уже другая версия), доступный на официальном сайте Microsoft. Разрядность пакета и системы должны соответствовать.

Шаг 2:
Необходимо настроить пути, для этого переходим во вкладку Debug — Properties:

“C:\Program Files\Microsoft HPC Pack 2008 SDK\Include”

В поле Library Directories:

“C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\amd64”

В поле с библиотеками, если стоит 32 разрядная версия, вместо amd64 нужно прописать i386.

Msmpi.lib

:

Шаг 3 :

Для настройки запуска необходимо перейти во вкладку Debugging и в поле Command указать:

“C:\Program Files\Microsoft HPC Pack 2008 SDK\Bin\mpiexec.exe”

В поле Command Arguments указать, например,

N 4 $(TargetPath)

Число 4 указывает на количество процессов.

Для запуска программы необходимо подключить библиотеку

Путь к проекту не должен содержать кириллицу. При возникновении ошибок можно воспользоваться Microsoft MPI, доступный по на сайте Microsoft.

Для этого после установки достаточно прописать в поле Command вкладки Debugging путь:

“C:\Program Files\Microsoft MPI\Bin\mpiexec.exe”

Также перед запуском программы не забудьте указать её разрядность:

Пример запуска программы с MPI :

#include #include using namespace std; int main(int argc, char **argv) { int rank, size; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); cout << "The number of processes: " << size << " my number is " << rank << endl; MPI_Finalize(); return 0; }

Работа программы на 2 узлах:

Аннотация: Лекция посвящена рассмотрению технологии MPI как стандарта параллельного программирования для систем с распределенной памятью. Рассматриваются основные режимы передачи данных. Вводятся такие понятия, как группы процессов и коммуникаторы. Рассматриваются основные типы данных, операции "точка-точка", коллективные операции, операции синхронизации и измерения времени.

Цель лекции: Лекция направлена на изучение общей методики разработки параллельных алгоритмов.

Видеозапись лекции - (объем - 134 МБ).

5.1. MPI: основные понятия и определения

Рассмотрим ряд понятий и определений, являющихся основополагающими для стандарта MPI .

5.1.1. Понятие параллельной программы

Под параллельной программой в рамках MPI понимается множество одновременно выполняемых процессов . Процессы могут выполняться на разных процессорах, но на одном процессоре могут располагаться и несколько процессов (в этом случае их исполнение осуществляется в режиме разделения времени). В предельном случае для выполнения параллельной программы может использоваться один процессор – как правило, такой способ применяется для начальной проверки правильности параллельной программы.

Каждый процесс параллельной программы порождается на основе копии одного и того же программного кода (модель SPMP ). Данный программный код, представленный в виде исполняемой программы, должен быть доступен в момент запуска параллельной программы на всех используемых процессорах. Исходный программный код для исполняемой программы разрабатывается на алгоритмических языках C или Fortran с использованием той или иной реализации библиотеки MPI.

Количество процессов и число используемых процессоров определяется в момент запуска параллельной программы средствами среды исполнения MPI-программ и в ходе вычислений меняться не может (в стандарте MPI-2 предусматривается возможность динамического изменения количества процессов). Все процессы программы последовательно перенумерованы от 0 до p-1 , где p есть общее количество процессов. Номер процесса именуется рангом процесса.

5.1.2. Операции передачи данных

Основу MPI составляют операции передачи сообщений. Среди предусмотренных в составе MPI функций различаются парные (point-to-point ) операции между двумя процессами и коллективные (collective ) коммуникационные действия для одновременного взаимодействия нескольких процессов.

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

Как уже отмечалось ранее, стандарт MPI предусматривает необходимость реализации большинства основных коллективных операций передачи данных – см. подразделы 5.2 и 5.4.

5.1.3. Понятие коммуникаторов

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

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

В ходе вычислений могут создаваться новые и удаляться существующие группы процессов и коммуникаторы. Один и тот же процесс может принадлежать разным группам и коммуникаторам. Все имеющиеся в параллельной программе процессы входят в состав создаваемого по умолчанию коммуникатора с идентификатором MPI_COMM_WORLD.

При необходимости передачи данных между процессами из разных групп необходимо создавать глобальный коммуникатор (intercommunicator ).

Подробное рассмотрение возможностей MPI для работы с группами и коммуникаторами будет выполнено в подразделе 5.6.

5.1.4. Типы данных

При выполнении операций передачи сообщений для указания передаваемых или получаемых данных в функциях MPI необходимо указывать тип пересылаемых данных. MPI содержит большой набор базовых типов данных, во многом совпадающих с типами данных в алгоритмических языках C и Fortran. Кроме того, в MPI имеются возможности для создания новых производных типов данных для более точного и краткого описания содержимого пересылаемых сообщений.

Подробное рассмотрение возможностей MPI для работы с производными типами данных будет выполнено в подразделе 5.5.

5.1.5. Виртуальные топологии

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

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

В MPI имеется возможность представления множества процессов в виде решетки произвольной размерности (см. подраздел 5.7). При этом, граничные процессы решеток могут быть объявлены соседними и, тем самым, на основе решеток могут быть определены структуры типа тор .

Кроме того, в MPI имеются средства и для формирования логических (виртуальных) топологий любого требуемого типа. Подробное рассмотрение возможностей MPI для работы с топологиями будет выполнено в подразделе 5.7.

И, наконец, последний ряд замечаний перед началом рассмотрения MPI:

  • Описание функций и все приводимые примеры программ будут представлены на алгоритмическом языке C; особенности использования MPI для алгоритмического языка Fortran будут даны в п. 5.8.1,
  • Краткая характеристика имеющихся реализаций библиотек MPI и общее описание среды выполнения MPI программ будут рассмотрены в п. 5.8.2,
  • Основное изложение возможностей MPI будет ориентировано на стандарт версии 1.2 (MPI-1 ); дополнительные свойства стандарта версии 2.0 буду представлены в п. 5.8.3.

Приступая к изучению MPI, можно отметить, что, с одной стороны, MPI достаточно сложен – в стандарте MPI предусматривается наличие более 125 функций. С другой стороны, структура MPI является тщательно продуманной – разработка параллельных программ может быть начата уже после рассмотрения всего лишь 6 функций MPI. Все дополнительные возможности MPI могут осваиваться по мере роста сложности разрабатываемых алгоритмов и программ. Именное в таком стиле – от простого к сложному – и будет далее представлен весь учебный материал по MPI.

5.2. Введение в разработку параллельных программ с использованием MPI

5.2.1. Основы MPI

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

5.2.1.1 Инициализация и завершение MPI программ

Первой вызываемой функцией MPI должна быть функция:

int MPI_Init (int *agrc, char ***argv);

для инициализации среды выполнения MPI-программы. Параметрами функции являются количество аргументов в командной строке и текст самой командной строки.

Последней вызываемой функцией MPI обязательно должна являться функция:

int MPI_Finalize (void);

Как результат, можно отметить, что структура параллельной программы, разработанная с использованием MPI, должна иметь следующий вид:

#include "mpi.h" int main (int argc, char *argv) { <программный код без использования MPI функций> MPI_Init (&agrc, &argv); <программный код с использованием MPI функций> MPI_Finalize(); <программный код без использования MPI функций> return 0; }

Следует отметить:

  1. Файл mpi.h содержит определения именованных констант, прототипов функций и типов данных библиотеки MPI,
  2. Функции MPI_Init и MPI_Finalize являются обязательными и должны быть выполнены (и только один раз) каждым процессом параллельной программы,
  3. Перед вызовом MPI_Init может быть использована функция MPI_Initialized для определения того, был ли ранее выполнен вызов MPI_Init .

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

Следует отметить:

  • Коммуникатор MPI_COMM_WORLD , как отмечалось ранее, создается по умолчанию и представляет все процессы выполняемой параллельной программы,
  • Ранг, получаемый при помощи функции MPI_Comm_rank , является рангом процесса, выполнившего вызов этой функции, т.е. переменная ProcRank будет принимать различные значения в разных процессах.

Распараллеливание на языке Си
Пример 3b . Распараллеливание на языке Фортран
Пример 4a . Определение характеристик системного таймера на языке Си
Пример 4b . Определение характеристик системного таймера на языке Фортран

1.4. Передача и прием сообщений между отдельными процессами

1.4.1. Операции типа точка-точка

1.4.2. Передача и прием сообщений с блокировкой

Пример 5a . Обмен сообщениями двух процессов на языке Си
Пример 5b . Обмен сообщениями двух процессов на языке Фортран
Пример 6a . Обмен сообщениями четных и нечетных процессов на языке Си
Пример 6b . Обмен сообщениями четных и нечетных процессов на языке Фортран
Пример 7a . Пересылка несуществующему процессу на языке Си
Пример 7b . Пересылка несуществующему процессу на языке Фортран
Пример 8a . Буферизованная посылка данных на языке Си
Пример 8b . Буферизованная посылка данных на языке Фортран
Пример 9a . Получение информации об атрибутах сообщения на языке Си
Пример 9b . Получение информации об атрибутах сообщения на языке Фортран
Пример 10a . Определение латентности и пропускной способности на языке Си
Пример 10b . Определение латентности и пропускной способности на языке Фортран

1.4.3. Передача и прием сообщений без блокировки

Пример 11a . Обмен по кольцевой топологии при помощи неблокирующих операций на языке Си
Пример 11b . Обмен по кольцевой топологии при помощи неблокирующих операций на языке Фортран
Пример 12a . Коммуникационная схема «мастер - рабочие» на языке Си
Пример 12b . Коммуникационная схема «мастер - рабочие» на языке Фортран
Пример 13a . Транспонирование матрицы на языке Си
Пример 13b . Транспонирование матрицы на языке Фортран

1.4.4. Отложенные запросы на взаимодействие

Пример 14a . Схема итерационного метода с обменом по кольцевой топологии при помощи отложенных запросов на языке Си
Пример 14b . Схема итерационного метода с обменом по кольцевой топологии при помощи отложенных запросов на языке Фортран

1.4.5. Тупиковые ситуации (deadlock)

Пример 15a . Обмен по кольцевой топологии при помощи процедуры MPI_Sendrecv на языке Си
Пример 15b . Обмен по кольцевой топологии при помощи процедуры MPI_SENDRECV на языке Фортран

1.5. Коллективные взаимодействия процессов

1.5.1. Общие положения

1.5.2. Барьер

Пример 16a . Моделирование барьерной синхронизации на языке Си
Пример 16b . Моделирование барьерной синхронизации на языке Фортран

1.5.3. Коллективные операции пересылки данных

1.5.4. Глобальные операции

Пример 17a . Моделирование глобального суммирования при помощи схемы сдваивания и коллективной операции MPI_Reduce на языке Си
Пример 17b . Моделирование глобального суммирования при помощи схемы сдваивания и коллективной операции MPI_Reduce на языке Фортран

1.5.5. Пользовательские глобальные операции

Пример 18a . Пользовательская глобальная функция на языке Си
Пример 18b . Пользовательская глобальная функция на языке Фортран

1.6. Группы и коммуникаторы

1.6.1. Общие положения

1.6.2. Операции с группами процессов

Пример 19a . Работа с группами на языке Си
Пример 19b . Работа с группами на языке Фортран

1.6.3. Операции с коммуникаторами

Пример 20a . Разбиение коммуникатора на языке Си
Пример 20b . Разбиение коммуникатора на языке Фортран
Пример 21a . Перенумерация процессов на языке Си
Пример 21b . Перенумерация процессов на языке Фортран

1.6.4. Интеркоммуникаторы

Пример 22a . Cхема «мастер - рабочие» с использованием интеркоммуникатора на языке Си
Пример 22b . Схема «мастер - рабочие» с использованием интеркоммуникатора на языке Фортран

1.6.5. Атрибуты

1.7. Виртуальные топологии

1.7.1. Общие положения

1.7.2. Декартова топология

1.7.3. Топология графа

Пример 23a . Cхема «мастер - рабочие» с использованием графовой топологии на языке Си
Пример 23b . Схема «мастер - рабочие» с использованием графовой топологии на языке Фортран

1.8. Пересылка разнотипных данных

1.8.1. Общие положения

1.8.2. Производные типы данных

Пример 24a . Перестановка столбцов матрицы в обратном порядке на языке Си
Пример 24b . Перестановка столбцов матрицы в обратном порядке на языке Фортран

1.8.3. Упаковка данных

Пример 25a . Пересылка упакованных данных на языке Си
Пример 25b . Пересылка упакованных данных на языке Фортран

1.9. Объект info

1.9.1. Общие положения

1.9.2. Работа с объектом info

1.10. Динамическое управление процессами

1.10.1. Общие положения

1.10.2.Порождение процессов

master.c
slave.c
Пример 26a. Схема «мастер - рабочие» с использованием порождения процессов на языке Си
master.f
slave.f
Пример 26b. Схема «мастер - рабочие» с использованием порождения процессов на языке Фортран

1.10.3. Клиент-серверная связь

server.c
client.c
Пример 27a. Обмен данными между сервером и клиентом посредством публичного имени на языке Си
server.f
client.f
Пример 27b. Обмен данными между сервером и клиентом посредством публичного имени на языке Фортран

1.10.4. Удаление связи процессов

1.10.5. Связь через сокеты

1.11. Односторонние коммуникации

1.11.1. Общие положения

1.11.2. Работа с окном

1.11.3. Передача данных

1.11.4. Синхронизация

Пример 28a
Пример 28b
Пример 29a . Обмен по кольцевой топологии при помощи односторонних коммуникаций на языке Си
Пример 29b . Обмен по кольцевой топологии при помощи односторонних коммуникаций на языке Фортран
Пример 30a . Обмен по кольцевой топологии при помощи односторонних коммуникаций на языке Си
Пример 30b . Обмен по кольцевой топологии при помощи односторонних коммуникаций на языке Фортран

1.12. Внешние интерфейсы

1.12.1. Обобщенные запросы

1.12.2. Информация из статуса

1.12.3. Нити

1.13. Параллельный ввод/вывод

1.13.1. Определения

1.13.2. Работа с файлами

1.13.3. Доступ к данным

Пример 31a . Буферизованное чтение из файла на языке Си
Пример 31b . Буферизованное чтение из файла на языке Фортран
Пример 32a . Коллективное чтение из файла на языке Си
Пример 32b . Коллективное чтение из файла на языке Фортран

1.14. Обработка ошибок

1.14.1. Общие положения

1.14.2. Обработчики ошибок, связанные с коммуникаторами

1.14.3. Обработчики ошибок, связанные с окнами

1.14.4. Обработчики ошибок, связанные с файлами

1.14.5. Дополнительные процедуры

1.14.6. Коды и классы ошибок

1.14.7. Вызов обработчиков ошибок

Пример 33a . Обработка ошибок на языке Си
Пример 33b . Обработка ошибок на языке Фортран

Глава 2 Технология параллельного программирования OpenMP

2.1. Введение

2.2. Основные понятия

2.2.1. Компиляция программы

Пример 34a . Условная компиляция на языке Си
Пример 34b
Пример 34c . Условная компиляция на языке Фортран

2.2.2. Модель параллельной программы

2.2.3. Директивы и процедуры

2.2.4. Выполнение программы

2.2.5. Замер времени

Пример 35a . Работа с системными таймерами на языке Си
Пример 35b . Работа с системными таймерами на языке Фортран

2.3. Параллельные и последовательные области

2.3.1. Директива parallel

Пример 36a . Параллельная область на языке Си
Пример 36b . Параллельная область на языке Фортран
Пример 37a . Опция reduction на языке Си
Пример 37b . Опция reduction на языке Фортран

2.3.2. Сокращенная запись

2.3.3. Переменные среды и вспомогательные процедуры

Пример 38a . Процедура omp_set_num_threads и опция num_threads на языке Си
Пример 38b . Процедура omp_set_num_threads и опция num_threads на языке Фортран
Пример 39a . Процедуры omp_set_dynamic и omp_get_dynamic на языке Си
Пример 39b . Процедуры omp_set_dynamic и omp_get_dynamic на языке Фортран
Пример 40a . Вложенные параллельные области на языке Си
Пример 40b . Вложенные параллельные области на языке Фортран
Пример 41a . Функция omp_in_parallel на языке Си
Пример 41b . Функция omp_in_parallel на языке Фортран

2.3.4. Директива single

Пример 42a . Директива single и опция nowait на языке Си
Пример 42b . Директива single и опция nowait на языке Фортран
Пример 43a . Опция copyprivate на языке Си
Пример 43b . Опция copyprivate на языке Фортран

2.3.5. Директива master

Пример 44a . Директива master на языке Си
Пример 44b . Директива master на языке Фортран

2.4. Модель данных

Пример 45a . Опция private на языке Си
Пример 45b . Опция private на языке Фортран
Пример 46a . Опция shared на языке Си
Пример 46b . Опция shared на языке Фортран
Пример 47a . Опция firstprivate на языке Си
Пример 47b . Опция firstprivate на языке Фортран
Пример 48a . Директива threadprivate на языке Си
Пример 48b . Директива threadprivate на языке Фортран
Пример 49a . Опция copyin на языке Си
Пример 49b . Опция copyin на языке Фортран

2.5. Распределение работы

2.5.1. Низкоуровневое распараллеливание

Пример 50a . Процедуры omp_get_num_threads и omp_get_thread_num на языке Си
Пример 50b . Процедуры omp_get_num_threads и omp_get_thread_num на языке Фортран

2.5.2. Параллельные циклы

Пример 51a . Директива for на языке Си
Пример 51b . Директива do на языке Фортран
Пример 52a . Опция schedule на языке Си
Пример 52b . Опция schedule на языке Фортран
Пример 53a . Опция schedule на языке Си

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

Основные принципы и пример
В качестве примера будет использоваться расчет экспоненты (e). Один из вариантов ее нахождения - ряд Тейлора:
e^x=∑((x^n)/n!) , где суммирование происходит от n=0 до бесконечности.

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

Количество слагаемых, которое будет рассчитываться в каждом отдельно взятом процессоре, зависит как и от длины интервала n, так и от имеющегося количества процессоров k, которые смогут участвовать в процессе вычисления. Так, например, если длина интервала n=4, а в вычислениях участвуют пять процессоров (k=5), то с первого по четвертый процессоры получат по одному слагаемому, а пятый будет не задействован. В случае же если n=10, а k=5, каждому процессору достанется по два слагаемых для вычисления.

Изначально, первый процессор с помощью функции широковещательной рассылки MPI_Bcast отправляет остальным значение заданной пользователями переменной n. В общем случае функция MPI_Bcast имеет следующий формат:
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm), где buffer – это адрес буфера с элементом, сount – количество элементов, datatype – соответствующий тип данных в MPI, root – ранг главного процессора, который занимается пересылкой, а comm- имя коммуникатора.
В моем случае в роли главного процессора, как уже говорилось, будет выступать первый процессор с рангом 0.

После того число n будет успешно отправлено, каждый процессор займется вычислением своих слагаемых. Для этого в каждом шаге цикла к числу i, которое изначально равно рангу процессора, будет прибавляться число, равное количеству процессоров участвующих в вычислениях. Если число в ходе следующих действий число i превысит заданное пользователем число n, выполнение цикла для данного процессора остановится.

В ходе выполнения цикла слагаемые будут прибавляться в отдельную переменную и, после его завершения, полученная сумма отправится в главный процессор. Для этого будет использоваться функция операции приведения MPI_Reduce. В общем виде она выглядит следующим образом:
int MPI_Reduce(void *buf, void *result, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)

Она объединяет элементы входного буфера каждого процесса в группе, используя операцию op, и возвращает объединенное значение в выходной буфер процесса с номером root. Результатом такой операции будет единственное значение, благодаря чему функция приведения и получила свое название.

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

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

Первостепенной задачей все же является нахождение значения экспоненты и если процессоры начнут вычислять каждый факториал каждого слагаемого раздельным образом, это может привести к прямо обратно эффекту, а именно значительной потери в производительности и скорости вычисления.
Объясняется это тем, что в данном случае начнется весьма большая нагрузка на коммуникационную среду, которая и без того зачастую является слабым звеном в системах параллельных вычислений. Если же вычисление факториала будет происходить на каждом процессоре частным образом, нагрузка на линии коммуникаций будет минимальна. Данный случай можно назвать хорошим примером того, что и задача распараллеливания тоже должна порой иметь свои границы.

Алгоритм выполнения кода
1. Из визуальной оболочки в программу передается значение числа n, которое затем с помощью функции широковещательной рассылки отправляется по всем процессорам.
2. При инициализации первого главного процессора, запускается таймер.
3. Каждый процессор выполняет цикл, где значением приращения является количество процессоров в системе. В каждой итерации цикла вычисляется слагаемое и сумма таких слагаемых сохраняется в переменную drobSum.
4. После завершения цикла каждый процессор суммирует свое значение drobSum к переменной Result, используя для этого функцию приведения MPI_Reduce.
5. После завершения расчетов на всех процессорах, первый главный процессор останавливает таймер и отправляет в поток вывода получившееся значение переменной Result.
6. В поток вывода отправляется также и отмеренное нашим таймером значение времени в милисекундах.
Листинг кода
Программа написана на С++, будем считать что аргументы для выполнения передаются из внешней оболочки. Код выглядит следующим образом:
#include "mpi.h"
#include
#include
using namespace std;

double Fact(int n)
{
if (n==0)
return 1;
else
return n*Fact(n-1);
}

int main(int argc, char *argv)
{
SetConsoleOutputCP(1251);
int n;
int myid;
int numprocs;
int i;
int rc;
long double drob,drobSum=0,Result, sum;
double startwtime = 0.0;
double endwtime;

N = atoi(argv);

if (rc= MPI_Init(&argc, &argv))
{
cout << "Ошибка запуска, выполнение остановлено " << endl;
MPI_Abort(MPI_COMM_WORLD, rc);
}

MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);

if (myid == 0)
{

Startwtime = MPI_Wtime();
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);

for (i = myid; i <= n; i += numprocs)
{
drob = 1/Fact(i);
drobSum += drob;
}

MPI_Reduce(&drobSum, &Result, 1, MPI_LONG_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
cout.precision(20);
if (myid == 0)
{
cout << Result << endl;
endwtime = MPI_Wtime();
cout << (endwtime-startwtime)*1000 << endl;
}

MPI_Finalize();
return 0;
}


* This source code was highlighted with Source Code Highlighter .
Вывод
Таким образом мы получили простенькую программу для подсчета экспоненты с использованием сразу нескольких процессоров. Наверное, узким местом является хранением самого результата, потому что с увеличением количества разрядов вмещать значение с использованием стандартных типов банально не выйдет и это место требует проработки. Пожалуй, достаточно рациональным решением является запись результата в файл, хотя, в виду чисто учебной функции этого примера, особо на этом внимание можно не акцентировать.

Если заметили ошибку, выделите фрагмент текста и нажмите Ctrl+Enter
ПОДЕЛИТЬСЯ:
NexxDigital - компьютеры и операционные системы