Интерфейс передачи сообщений ( MPI) - это стандартизованный переносимый стандарт передачи сообщений, предназначенный для работы в архитектурах параллельных вычислений. MPI стандарт определяет синтаксис и семантика из библиотеки подпрограмм, которые являются полезными для широкого круга пользователей, пишущих портативных программы передачи сообщений в C, C ++ и Fortran. Существует несколько реализаций MPI с открытым исходным кодом, которые способствовали развитию индустрии параллельного программного обеспечения и поощряли разработку переносимых и масштабируемых крупномасштабных параллельных приложений.
Работа над интерфейсом передачи сообщений началась летом 1991 года, когда небольшая группа исследователей начала обсуждения в горном ретрите в Австрии. Результатом этого обсуждения стал семинар по стандартам передачи сообщений в среде с распределенной памятью, состоявшийся 29–30 апреля 1992 г. в Вильямсбурге, штат Вирджиния. Участники Williamsburg обсудили основные функции, необходимые для стандартного интерфейса передачи сообщений, и создали рабочую группу для продолжения процесса стандартизации. Джек Донгарра, Тони Хей и Дэвид Уолкер выдвинули предварительный проект предложения «MPI1» в ноябре 1992 года. В ноябре 1992 года в Миннеаполисе состоялась встреча рабочей группы MPI, на которой было решено поставить процесс стандартизации на более высокий уровень. формальная основа. Рабочая группа MPI собиралась каждые 6 недель в течение первых 9 месяцев 1993 года. Проект стандарта MPI был представлен на конференции Supercomputing '93 в ноябре 1993 года. После периода публичных комментариев, которые привели к некоторым изменениям в MPI, версия 1.0 MPI был выпущен в июне 1994 года. Эти встречи и обсуждения по электронной почте вместе составляли форум MPI, членство в котором было открыто для всех членов сообщества высокопроизводительных вычислений.
В MPI участвовало около 80 человек из 40 организаций, в основном из США и Европы. Большинство основных производителей компьютеров для параллельной работы участвовали в разработке MPI, сотрудничая с исследователями из университетов, государственных лабораторий и промышленности.
MPI предоставляет поставщикам параллельного оборудования четко определенный базовый набор процедур, которые можно эффективно реализовать. В результате поставщики оборудования могут использовать этот набор стандартных низкоуровневых подпрограмм для создания высокоуровневых подпрограмм для среды связи с распределенной памятью, поставляемой с их параллельными машинами. MPI предоставляет простой в использовании переносимый интерфейс для базового пользователя, но достаточно мощный, чтобы позволить программистам использовать высокопроизводительные операции передачи сообщений, доступные на продвинутых машинах.
Пытаясь создать универсальный стандарт для передачи сообщений, исследователи не основывали его на единой системе, а включили в него наиболее полезные функции нескольких систем, в том числе разработанных IBM, Intel, nCUBE, PVM, Express, P4 и PARMACS.. Парадигма передачи сообщений привлекательна из-за широкой переносимости и может использоваться при обмене данными для мультипроцессоров с распределенной и общей памятью, сетей рабочих станций и комбинации этих элементов. Парадигма может применяться в нескольких параметрах, независимо от скорости сети или архитектуры памяти.
Поддержка встреч MPI была частично предоставлена DARPA и Национальным научным фондом США (NSF) в рамках гранта ASC-9310330, Соглашения о сотрудничестве между научным и технологическим центром NSF номер CCR-8809615, а также Европейской комиссией через проект Esprit Project P6643. Университет Теннесси также финансовые взносы в MPI Forum.
MPI - это протокол связи для программирования параллельных компьютеров. Поддерживаются как двухточечная, так и коллективная связь. MPI «представляет собой интерфейс прикладного программиста с передачей сообщений вместе с протоколом и семантическими спецификациями, определяющими, как его функции должны вести себя в любой реализации». Цели MPI - высокая производительность, масштабируемость и переносимость. MPI остается доминирующей моделью, используемой сегодня в высокопроизводительных вычислениях.
MPI не санкционирован каким-либо крупным органом по стандартизации; тем не менее, он стал де-факто стандартом для взаимодействия между процессами, моделирующими параллельную программу, работающую в системе с распределенной памятью. Реальные суперкомпьютеры с распределенной памятью, такие как компьютерные кластеры, часто запускают такие программы.
Основная модель MPI-1 не имеет концепции разделяемой памяти, а MPI-2 имеет только ограниченную концепцию распределенной разделяемой памяти. Тем не менее, программы MPI регулярно запускаются на компьютерах с общей памятью, и как MPICH, так и Open MPI могут использовать общую память для передачи сообщений, если она доступна. Разработка программ на основе модели MPI (в отличие от явных моделей разделяемой памяти ) имеет преимущества перед архитектурами NUMA, поскольку MPI поощряет локальность памяти. Явное программирование с разделяемой памятью было введено в MPI-3.
Хотя MPI относится к уровням 5 и выше эталонной модели OSI, реализации могут охватывать большинство уровней с сокетами и протоколом управления передачей (TCP), используемыми на транспортном уровне.
Большинство реализаций MPI состоят из определенного набора подпрограмм, вызываемых напрямую из C, C ++, Fortran (т. Е. API) и любого языка, способного взаимодействовать с такими библиотеками, включая C #, Java или Python. Преимуществами MPI перед более старыми библиотеками передачи сообщений являются переносимость (поскольку MPI был реализован почти для каждой архитектуры распределенной памяти) и скорость (поскольку каждая реализация в принципе оптимизирована для оборудования, на котором она работает).
MPI использует независимые от языка спецификации (LIS) для вызовов и языковых привязок. Первый стандарт MPI определял привязки ANSI C и Fortran-77 вместе с LIS. Проект был представлен на Supercomputing 1994 (ноябрь 1994 г.) и вскоре после этого был доработан. Около 128 функций составляют стандарт MPI-1.3, который был выпущен в качестве последнего конца серии MPI-1 в 2008 году.
В настоящее время стандарт имеет несколько версий: версия 1.3 (обычно сокращенно MPI-1), которая подчеркивает передачу сообщений и имеет статическую среду выполнения, MPI-2.2 (MPI-2), которая включает новые функции, такие как параллельный ввод-вывод, динамическое управление процессами и операции с удаленной памятью, а также MPI-3.1 (MPI-3), который включает расширения для коллективных операций с неблокирующими версиями и расширения для односторонних операций. LIS MPI-2 определяет более 500 функций и предоставляет языковые привязки для ISO C, ISO C ++ и Fortran 90. Также была добавлена возможность взаимодействия объектов, чтобы упростить программирование передачи сообщений на разных языках. Побочным эффектом стандартизации MPI-2, завершенной в 1996 году, было уточнение стандарта MPI-1, создание MPI-1.2.
MPI-2 в основном является надмножеством MPI-1, хотя некоторые функции устарели. Программы MPI-1.3 по-прежнему работают в реализациях MPI, совместимых со стандартом MPI-2.
MPI-3 включает новые привязки Fortran 2008, но при этом удаляет устаревшие привязки C ++, а также многие устаревшие процедуры и объекты MPI.
MPI часто сравнивают с Parallel Virtual Machine (PVM), которая представляет собой популярную распределенную среду и систему передачи сообщений, разработанную в 1989 году и являющуюся одной из систем, которая мотивировала необходимость стандартной параллельной передачи сообщений. Модели потокового программирования с общей памятью (такие как Pthreads и OpenMP ) и программирование с передачей сообщений (MPI / PVM) можно рассматривать как взаимодополняющие и иногда использовались вместе, например, на серверах с несколькими большими узлами с общей памятью.
Интерфейс MPI предназначен для обеспечения необходимой виртуальной топологии, синхронизации и функциональности связи между набором процессов (которые были сопоставлены с узлами / серверами / экземплярами компьютеров) независимым от языка способом, с синтаксисом, зависящим от языка (привязки), плюс несколько языковых функций. Программы MPI всегда работают с процессами, но программисты обычно называют процессы процессорами. Обычно для максимальной производительности каждому процессору (или ядру в многоядерной машине) назначается только один процесс. Это назначение происходит во время выполнения через агент, запускающий программу MPI, обычно называемую mpirun или mpiexec.
Функции библиотеки MPI включают в себя, но не ограничиваются ими, точка-точка сближения типа передачи / приема операции, выбирая между декартовой или графа -подобных логической топологии процесса, обмен данными между парами процессов (отправка / прием операций), сочетающий в себе частичное результаты вычислений (операции сбора и сокращения), синхронизации узлов (барьерная операция), а также получение сетевой информации, такой как количество процессов в вычислительном сеансе, текущий идентификатор процессора, которому сопоставлен процесс, соседние процессы, доступные в логическая топология и так далее. Операции «точка-точка» бывают синхронными, асинхронными, буферизованными и готовыми, чтобы обеспечить как относительно более сильную, так и более слабую семантику для аспектов синхронизации при рандеву-отправке. Многие выдающиеся операции возможны в асинхронном режиме в большинстве реализаций.
MPI-1 и MPI-2 позволяют реализации, которые перекрывают обмен данными и вычисления, но практика и теория различаются. MPI также определяет Потокобезопасную интерфейсы, которые имеют сцепление и сцепные стратегии, которые помогут избежать скрытых состояний в интерфейсе. Написать многопоточный двухточечный код MPI относительно легко, и некоторые реализации поддерживают такой код. Многопоточное коллективное общение лучше всего осуществлять с несколькими копиями коммуникаторов, как описано ниже.
MPI предоставляет несколько функций. Следующие ниже концепции обеспечивают контекст для всех этих возможностей и помогают программисту решить, какие функции использовать в своих прикладных программах. Четыре из восьми основных концепций MPI уникальны для MPI-2.
Объекты коммуникатора соединяют группы процессов в сеансе MPI. Каждый коммуникатор дает каждому включенному процессу независимый идентификатор и упорядочивает содержащиеся в нем процессы в упорядоченной топологии. MPI также имеет явные группы, но они в основном хороши для организации и реорганизации групп процессов до того, как будет создан другой коммуникатор. MPI понимает операции внутрикоммуникаторной отдельной группы и двустороннюю межкоммуникаторную связь. В MPI-1 наиболее распространены одиночные групповые операции. Двусторонние операции чаще всего появляются в MPI-2, где они включают коллективное общение и динамическое внутрипроцессное управление.
Коммуникаторы можно разделить с помощью нескольких команд MPI. Эти команды включают MPI_COMM_SPLIT
, где каждый процесс присоединяется к одному из нескольких цветных субкоммуникаторов, объявляя себя имеющим этот цвет.
Ряд важных функций MPI включает связь между двумя конкретными процессами. Популярным примером является то MPI_Send
, что позволяет одному указанному процессу отправлять сообщение второму указанному процессу. Двухточечные операции, как их называют, особенно полезны при структурированном или нерегулярном обмене данными, например, в архитектуре параллельных данных, в которой каждый процессор регулярно обменивает области данных с определенными другими процессорами между этапами вычислений, или ведущий- ведомая архитектура, в которой ведущее устройство отправляет новые данные задачи ведомому всякий раз, когда предыдущая задача завершена.
MPI-1 определяет механизмы как для блокирующих, так и для неблокирующих механизмов связи точка-точка, а также так называемый механизм «готовой отправки», посредством которого запрос на отправку может быть сделан только тогда, когда соответствующий запрос приема уже был сделан..
Коллективные функции включают взаимодействие между всеми процессами в группе процессов (что может означать весь пул процессов или определенное программой подмножество). Типичная функция - MPI_Bcast
звонок (сокращение от « трансляция »). Эта функция берет данные с одного узла и отправляет их всем процессам в группе процессов. Обратная операция - это MPI_Reduce
вызов, который берет данные от всех процессов в группе, выполняет операцию (например, суммирование) и сохраняет результаты на одном узле. MPI_Reduce
часто бывает полезно в начале или в конце больших распределенных вычислений, когда каждый процессор обрабатывает часть данных, а затем объединяет их в результат.
Другие операции выполняют более сложные задачи, например, MPI_Alltoall
переупорядочивают n элементов данных таким образом, что n- й узел получает n- й элемент данных от каждого.
Многие функции MPI требуют, чтобы вы указали тип данных, которые пересылаются между процессами. Это связано с тем, что MPI нацелен на поддержку гетерогенных сред, в которых типы могут быть представлены по-разному на разных узлах (например, они могут работать с разными архитектурами ЦП с разным порядком байтов ), и в этом случае реализации MPI могут выполнять преобразование данных. Поскольку язык C не позволяет типа сам быть принят в качестве параметра, MPI предопределены константы MPI_INT
, MPI_CHAR
, MPI_DOUBLE
переписываться с int
, char
, double
и т.д.
Вот пример на C, который передает массивы int
s от всех процессов одному. Один принимающий процесс называется «корневым» процессом, и это может быть любой назначенный процесс, но обычно это будет процесс 0. Все процессы запрашивают отправку своих массивов в корень с помощью MPI_Gather
, что эквивалентно наличию каждого процесса (включая root сам), MPI_Send
и root выполняет соответствующее количество упорядоченных MPI_Recv
вызовов, чтобы собрать все эти массивы в более крупный:
int send_array[100]; int root = 0; /* or whatever */ int num_procs, *recv_array; MPI_Comm_size(comm, amp;num_procs); recv_array = malloc(num_procs * sizeof(send_array)); MPI_Gather(send_array, sizeof(send_array) / sizeof(*send_array), MPI_INT, recv_array, sizeof(send_array) / sizeof(*send_array), MPI_INT, root, comm);
Однако вы можете вместо этого отправлять данные одним блоком, а не 100 int
с. Для этого определите производный тип данных «непрерывный блок»:
MPI_Datatype newtype; MPI_Type_contiguous(100, MPI_INT, amp;newtype); MPI_Type_commit(amp;newtype); MPI_Gather(array, 1, newtype, receive_array, 1, newtype, root, comm);
Для передачи класса или структуры данных MPI_Type_create_struct
создает тип MPI_predefined
данных, производный от MPI, из типов данных, как показано ниже:
int MPI_Type_create_struct(int count, int *blocklen, MPI_Aint *disp, MPI_Datatype *type, MPI_Datatype *newtype)
куда:
count
это число блоков, и задает длину (в элементах) из массивов blocklen
, disp
и type
.blocklen
содержит номера элементов в каждом блоке,disp
содержит байтовые смещения каждого блока,type
содержит типы элементов в каждом блоке.newtype
(вывод) содержит новый производный тип, созданный этой функциейdisp
(Смещения) массив необходим для выравнивания структуры данных, так как компилятор может колодки переменных в классе или структуру данных. Самый безопасный способ найти расстояние между разными полями - получить их адреса в памяти. Это делается с помощью MPI_Get_address
, который обычно совпадает с amp;
оператором C, но это может быть неверно при работе с сегментацией памяти.
Передача структуры данных в виде одного блока значительно быстрее, чем передача одного элемента за раз, особенно если операция должна быть повторена. Это связано с тем, что блоки фиксированного размера не требуют сериализации во время передачи.
Учитывая следующие структуры данных:
struct A { int f; short p; }; struct B { struct A a; int pp, vp; };
Вот код C для создания типа данных, производного от MPI:
static const int blocklen[] = {1, 1, 1, 1}; static const MPI_Aint disp[] = { offsetof(struct B, a) + offsetof(struct A, f), offsetof(struct B, a) + offsetof(struct A, p), offsetof(struct B, pp), offsetof(struct B, vp) }; static MPI_Datatype type[] = {MPI_INT, MPI_SHORT, MPI_INT, MPI_INT}; MPI_Datatype newtype; MPI_Type_create_struct(sizeof(type) / sizeof(*type), blocklen, disp, type, amp;newtype); MPI_Type_commit(amp;newtype);
MPI-2 определяет три операции, односторонние связи, MPI_Put
, MPI_Get
, и MPI_Accumulate
, будучи записью в удаленной памяти, чтения из удаленной памяти, и операции восстановления на одной и той же памяти через ряд задач, соответственно. Также определены три различных метода синхронизации этого обмена данными (глобальная, попарная и удаленная блокировки), поскольку спецификация не гарантирует, что эти операции выполняются до точки синхронизации.
Эти типы вызовов часто могут быть полезны для алгоритмов, в которых синхронизация была бы неудобной (например, распределенное умножение матриц ) или где желательно, чтобы задачи могли сбалансировать свою нагрузку, в то время как другие процессоры работают с данными.
Ключевым аспектом является «способность процесса MPI участвовать в создании новых процессов MPI или устанавливать связь с процессами MPI, которые были запущены отдельно». Спецификация MPI-2 описывает три основных интерфейса, с помощью которых процессы MPI могут динамически устанавливать связь MPI_Comm_spawn
, MPI_Comm_accept
/ MPI_Comm_connect
и MPI_Comm_join
. MPI_Comm_spawn
Интерфейс позволяет процесс MPI порождать количество экземпляров названного процесса MPI. Вновь созданный набор процессов MPI формирует новый MPI_COMM_WORLD
интракоммуникатор, но может связываться с родителем и интеркоммуникатором, возвращаемым функцией. MPI_Comm_spawn_multiple
- это альтернативный интерфейс, который позволяет создавать разные экземпляры как разные двоичные файлы с разными аргументами.
Функция параллельного ввода-вывода иногда называется MPI-IO и относится к набору функций, предназначенных для абстрагирования управления вводом-выводом в распределенных системах в MPI и обеспечения легкого доступа к файлам шаблонным способом с использованием существующих функций производных типов данных..
Небольшое исследование, проведенное по этой функции, показывает, что получение высокого прироста производительности с помощью MPI-IO может оказаться нетривиальным. Например, реализация умножения разреженной матрицы на вектор с использованием библиотеки ввода-вывода MPI демонстрирует общее поведение с незначительным приростом производительности, но эти результаты неубедительны. Только после того, как идея коллективного ввода-вывода была реализована в MPI-IO, MPI-IO начал получать широкое распространение. Коллективный ввод-вывод существенно увеличивает пропускную способность ввода-вывода приложений за счет того, что процессы коллективно преобразуют небольшие и несмежные операции ввода-вывода в большие и непрерывные, тем самым уменьшая накладные расходы на блокировку и поиск диска. Благодаря огромным преимуществам в производительности MPI-IO также стал базовым уровнем ввода-вывода для многих современных библиотек ввода-вывода, таких как HDF5 и Parallel NetCDF. Его популярность также подтолкнула к исследованиям по оптимизации коллективного ввода-вывода, таким как ввод-вывод с учетом макета и межфайловая агрегация.
Многие другие разработки являются производными от MPICH, LAM и других разработок, включая, помимо прочего, коммерческие реализации от HP, Intel, Microsoft и NEC.
Хотя спецификации предписывают интерфейс C и Fortran, язык, используемый для реализации MPI, не ограничивается соответствием языку или языкам, которые он стремится поддерживать во время выполнения. Большинство реализаций объединяют C, C ++ и язык ассемблера и предназначены для программистов на C, C ++ и Fortran. Привязки доступны для многих других языков, включая Perl, Python, R, Ruby, Java и CL (см. # Привязки языков).
В ABI из MPI реализаций грубо разделены между MPICH и OpenMP производных, так что библиотека из одной семьи работает как капля в замене одного из того же семейства, но прямая замена всей семьи невозможно. Французский CEA поддерживает интерфейс оболочки для облегчения таких переключений.
Аппаратные исследования MPI фокусируются на реализации MPI непосредственно в аппаратном обеспечении, например, через процессор в памяти, встраивая операции MPI в микросхему микросхем RAM в каждом узле. Подразумевается, что этот подход не зависит от языка, операционной системы и процессора, но не может быть легко обновлен или удален.
Другой подход заключался в добавлении аппаратного ускорения к одной или нескольким частям операции, включая аппаратную обработку очередей MPI и использование RDMA для прямой передачи данных между памятью и сетевым интерфейсом без вмешательства процессора или ядра ОС.
mpicc (и аналогично mpic ++, mpif90 и т. д.) - это программа, которая оборачивает существующий компилятор для установки необходимых флагов командной строки при компиляции кода, использующего MPI. Обычно он добавляет несколько флагов, которые позволяют скомпилировать код и связать его с библиотекой MPI.
Привязки - это библиотеки, которые расширяют поддержку MPI на другие языки путем обертывания существующей реализации MPI, такой как MPICH или Open MPI.
Двумя управляемыми реализациями .NET Common Language Infrastructure являются Pure Mpi.NET и MPI.NET, исследовательская работа в Университете Индианы под лицензией в стиле BSD. Он совместим с Mono и может в полной мере использовать базовые сетевые структуры MPI с низкой задержкой.
Хотя Java не имеет официальной привязки MPI, несколько групп пытаются объединить их с разной степенью успеха и совместимости. Одной из первых попыток была mpiJava Брайана Карпентера, по сути, набор оболочек Java Native Interface (JNI) для локальной библиотеки C MPI, что привело к гибридной реализации с ограниченной переносимостью, которая также должна быть скомпилирована для конкретной используемой библиотеки MPI..
Однако в этом исходном проекте также был определен mpiJava API ( де-факто MPI API для Java, который внимательно следил за эквивалентными привязками C ++), который был принят в других последующих проектах Java MPI. Менее используемым API является MPJ API, который был разработан, чтобы быть более объектно-ориентированным и приближенным к соглашениям о кодировании Sun Microsystems. Помимо API, библиотеки Java MPI могут либо зависеть от локальной библиотеки MPI, либо реализовывать функции передачи сообщений в Java, в то время как некоторые, такие как P2P-MPI, также обеспечивают одноранговую функциональность и позволяют работать со смешанной платформой.
Некоторые из наиболее сложных частей Java / MPI возникают из-за характеристик Java, таких как отсутствие явных указателей и линейного адресного пространства памяти для его объектов, что делает перенос многомерных массивов и сложных объектов неэффективным. Обходные обычно включают передачу одной линии в то время, и / или при выполнении явного де- сериализации и литье на оба передающие и принимающие концах, имитируя C или Fortran-подобные массивам путем использованием одномерного массива, а указатели на примитивные типы, использование одноэлементных массивов, что привело к созданию стилей программирования, весьма далеких от соглашений Java.
Еще одна система передачи сообщений Java - MPJ Express. Последние версии могут быть выполнены в кластерной и многоядерной конфигурациях. В кластерной конфигурации он может выполнять параллельные Java-приложения в кластерах и облаках. Здесь сокеты Java или специализированные межсоединения ввода-вывода, такие как Myrinet, могут поддерживать обмен сообщениями между процессами MPJ Express. Он также может использовать собственную реализацию MPI на языке C, используя собственное устройство. В многоядерной конфигурации параллельное приложение Java выполняется на многоядерных процессорах. В этом режиме процессы MPJ Express представлены потоками Java.
Julia язык обертка для MPI, была использована и оказалась быстрее, чем на C или Fortran.
Существует несколько академических реализаций MPI с использованием MATLAB. MATLAB имеет собственную библиотеку параллельных расширений, реализованную с использованием MPI и PVM.
Модуль OCamlMPI реализует большое количество функций MPI и активно используется в научных вычислениях. Программа OCaml, состоящая из 11 000 строк, была «преобразована в MPI» с использованием этого модуля, с дополнительными 500 строками кода и небольшой реструктуризацией и работала с превосходными результатами на 170 узлах суперкомпьютера.
Реализации MPI в Python включают: pyMPI, mpi4py, pypar, MYMPI и подмодуль MPI в ScientificPython. pyMPI примечателен тем, что это вариант интерпретатора python, в то время как модуль pypar, MYMPI и ScientificPython являются модулями импорта. Они поручают кодеру решать, кому MPI_Init
принадлежит вызов.
Недавно библиотеки Boost C ++ приобрели Boost: MPI, который включает привязки MPI Python. Это особенно помогает при смешивании C ++ и Python. По состоянию на октябрь 2016 года Boost: привязки MPI Python по-прежнему содержат нефиксированные ошибки упаковки в CentOS.
R- привязки MPI включают Rmpi и pbdMPI, где Rmpi фокусируется на параллелизме менеджеров и рабочих, а pbdMPI фокусируется на параллелизме SPMD. Обе реализации полностью поддерживают Open MPI или MPICH2.
Вот и "Привет, мир!" программа на MPI, написанная на C. В этом примере мы отправляем приветственное сообщение каждому процессору, тривиально обрабатываем его, возвращаем результаты основному процессу и распечатываем сообщения.
/* "Hello World" MPI Test Program */ #include lt;assert.hgt; #include lt;stdio.hgt; #include lt;string.hgt; #include lt;mpi.hgt; int main(int argc, char **argv) { char buf[256]; int my_rank, num_procs; /* Initialize the infrastructure necessary for communication */ MPI_Init(amp;argc, amp;argv); /* Identify this process */ MPI_Comm_rank(MPI_COMM_WORLD, amp;my_rank); /* Find out how many total processes are active */ MPI_Comm_size(MPI_COMM_WORLD, amp;num_procs); /* Until this point, all programs have been doing exactly the same. Here, we check the rank to distinguish the roles of the programs */ if (my_rank == 0) { int other_rank; printf("We have %i processes.\n", num_procs); /* Send messages to all other processes */ for (other_rank = 1; other_rank lt; num_procs; other_rank++) { sprintf(buf, "Hello %i!", other_rank); MPI_Send(buf, sizeof(buf), MPI_CHAR, other_rank, 0, MPI_COMM_WORLD); } /* Receive messages from all other process */ for (other_rank = 1; other_rank lt; num_procs; other_rank++) { MPI_Recv(buf, sizeof(buf), MPI_CHAR, other_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); printf("%s\n", buf); } } else { /* Receive message from process #0 */ MPI_Recv(buf, sizeof(buf), MPI_CHAR, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); assert(memcmp(buf, "Hello ", 6) == 0); /* Send message to process #0 */ sprintf(buf, "Process %i reporting for duty.", my_rank); MPI_Send(buf, sizeof(buf), MPI_CHAR, 0, 0, MPI_COMM_WORLD); } /* Tear down the communication infrastructure */ MPI_Finalize(); return 0; }
При запуске с 4 процессами он должен выдать следующий результат:
$ mpicc example.c amp;amp; mpiexec -n 4./a.out We have 4 processes. Process 1 reporting for duty. Process 2 reporting for duty. Process 3 reporting for duty.
Вот mpiexec
команда, используемая для выполнения примера программы с 4 процессами, каждый из которых является независимым экземпляром программы во время выполнения и имеет присвоенные ранги (т.е. числовые идентификаторы) 0, 1, 2 и 3. Имя mpiexec
рекомендуется стандарт MPI, хотя некоторые реализации предоставляют аналогичную команду под этим именем mpirun
. Это MPI_COMM_WORLD
коммуникатор, который состоит из всех процессов.
Тем самым упрощается, но не требуется, модель программирования « одна программа - несколько данных» ( SPMD ); многие реализации MPI позволяют запускать несколько разных исполняемых файлов в одном задании MPI. У каждого процесса есть свой ранг, общее количество процессов в мире и возможность общаться между ними либо с помощью двухточечной связи (отправка / получение), либо посредством коллективного взаимодействия между группой. Для MPI достаточно предоставить программе в стиле SPMD MPI_COMM_WORLD
свой ранг и размер мира, чтобы алгоритмы могли решать, что им делать. В более реалистичных ситуациях управление вводом-выводом осуществляется более тщательно, чем в этом примере. MPI не определяет, как стандартный ввод-вывод (stdin, stdout, stderr) должен работать в данной системе. Обычно он работает должным образом в процессе ранга 0, а некоторые реализации также захватывают и направляют выходные данные других процессов.
MPI использует понятие процесса, а не процессора. Копии программ отображаются на процессоры средой выполнения MPI. В этом смысле параллельная машина может отображаться на один физический процессор или на N процессоров, где N - количество доступных процессоров, или даже что-то среднее между ними. Для максимального параллельного ускорения используется больше физических процессоров. Этот пример подстраивает свое поведение к размеру мира N, поэтому он также стремится масштабироваться до конфигурации среды выполнения без компиляции для каждого варианта размера, хотя решения во время выполнения могут варьироваться в зависимости от этого абсолютного количества доступного параллелизма.
Принятие MPI-1.2 было универсальным, особенно в кластерных вычислениях, но принятие MPI-2.1 было более ограниченным. Проблемы включают:
Некоторые аспекты будущего MPI кажутся убедительными; другие в меньшей степени. MPI Forum вновь созвана в 2007 году для уточнения некоторых MPI-2 вопросы и изучить разработки для возможного MPI-3, в результате чего в версии MPI-3.0 (сентябрь 2012) и MPI-3.1 (июнь 2015).
Архитектуры меняются за счет большего внутреннего параллелизма ( многоядерный ), лучшего детального управления параллелизмом (многопоточность, сходство) и большего количества уровней иерархии памяти. Многопоточные программы могут легче использовать преимущества этих разработок, чем однопоточные приложения. Это уже привело к появлению отдельных дополнительных стандартов для симметричной многопроцессорной обработки, а именно OpenMP. MPI-2 определяет, как соответствующие стандарту реализации должны решать проблемы многопоточности, но не требует, чтобы реализации были многопоточными или даже поточно-ориентированными. MPI-3 добавляет возможность использовать параллелизм с общей памятью внутри узла. Реализации MPI, такие как Adaptive MPI, Hybrid MPI, Fine-Grained MPI, MPC и другие, предлагают расширения стандарта MPI, которые решают различные проблемы в MPI.
Астрофизик Джонатан Дурси написал статью, в которой назвал MPI устаревшим, указав на новые технологии, такие как язык Chapel, Unified Parallel C, Hadoop, Spark и Flink.