Повышаю. Программа MPI состоит из множества взаимодействующих процессов (возможно, работающих на разных компьютерах), которые общаются между собой путем передачи сообщений. Повышаю. MPI - это библиотека (как и MPI нижнего уровня), а не язык, поэтому первый шаг в увеличении. MPI - это создание объекта<mpi::environment>, который инициализирует среду MPI и обеспечивает связь между процессами. Объект<mpi::environment>инициализируется с помощью аргументов программы (которые он может изменить) в вашей основной программе. Создание этого объекта инициализирует MPI, а его разрушение завершит MPI. Подавляющее большинство Boost. MPI программы, экземпляр<mpi::environment>будет объявлен в<main>в самом начале программы.
Связь с MPI всегда происходит поверхкоммуникатора, который может быть создан просто по умолчанию-конструируя объект типа<mpi::communicator>. Затем этот коммуникатор может быть запрошен, чтобы определить, сколько процессов выполняется («размер» коммуникатора) и дать уникальное число каждому процессу, от нуля до размера коммуникатора (т.е. «ранг» процесса):
#include<boost/mpi/environment.hpp>#include<boost/mpi/communicator.hpp>#include<iostream>namespacempi=boost::mpi;intmain(){mpi::environmentenv;mpi::communicatorworld;std::cout<<"I am process "<<world.rank()<<" of "<<world.size()<<"."<<std::endl;return0;}
Например, если вы запустите эту программу с 7 процессами, вы получите выход, такой как:
I am process 5 of 7.
I am process 0 of 7.
I am process 1 of 7.
I am process 6 of 7.
I am process 2 of 7.
I am process 4 of 7.
I am process 3 of 7.
Конечно, процессы могут выполняться в разном порядке каждый раз, поэтому ряды не могут быть строго увеличены. Более интересно то, что текст может полностью испортиться, потому что один процесс может начать писать «Я — процесс» до того, как другой процесс закончит писать «7».
Если у вас все еще есть библиотека MPI, поддерживающая только MPI 1.1, вам нужно будет передать аргументы командной строки конструктору окружения, как показано в этом примере:
#include<boost/mpi/environment.hpp>#include<boost/mpi/communicator.hpp>#include<iostream>namespacempi=boost::mpi;intmain(intargc,char*argv[]){mpi::environmentenv(argc,argv);mpi::communicatorworld;std::cout<<"I am process "<<world.rank()<<" of "<<world.size()<<"."<<std::endl;return0;}
Как библиотека передачи сообщений, основная цель MPI заключается в рутинных сообщениях от одного процесса к другому, то есть от точки к точке. MPI содержит процедуры, которые могут отправлять сообщения, получать сообщения и запрашивать, доступны ли сообщения. Каждое сообщение имеет исходный процесс, целевой процесс, тег и полезную нагрузку, содержащую произвольные данные. Исходным и целевым процессами являются ранги отправителя и получателя сообщения соответственно. Теги - это целые числа, которые позволяют получателю различать различные сообщения, поступающие от одного и того же отправителя.
Следующая программа использует два процесса MPI, чтобы написать «Привет, мир!» на экране<hello_world.cpp>:
Первый процессор (ранг 0) передает сообщение «Привет» второму процессору (ранг 1) с помощью тега 0. Второй процессор печатает полученную строку вместе с запятой, а затем передает сообщение «мир» обратно в процессор 0 с другим тегом. Затем первый процессор записывает это сообщение с помощью «!» и выходит. Все посылки выполняются методом<communicator::send>, и все приемники используют соответствующий<communicator::recv>вызов.
Non-blocking communication
Операции связи MPI по умолчанию -<send>и<recv>- могут подождать, пока вся передача не будет завершена, прежде чем они смогут вернуться. Иногда этоблокирующееповедение оказывает негативное влияние на производительность, потому что отправитель может выполнять полезные вычисления, пока он ждет передачи. Более важными, однако, являются случаи, когда несколько операций связи должны происходить одновременно, например, процесс будет одновременно отправлять и получать.
Давайте вернемся к нашей программе «Привет, мир!» из предыдущего раздела. Ядро этой программы передает два сообщения:
Первый процесс передает сообщение второму процессу, затем готовится к получению сообщения. Второй процесс выполняет отправку и получение в обратном порядке. Тем не менее, эта последовательность событий — это просто последовательность, что означает, что по существу нет параллелизма. Мы можем использовать неблокирующую связь для обеспечения одновременной передачи двух сообщений<hello_world_nonblocking.cpp>:
Мы заменили призывы к<communicator::send>и<communicator::recv>членам аналогичными призывами к их неблокирующим коллегам<communicator::isend>и<communicator::irecv>. Префиксiуказывает, что операции немедленно возвращаются с объектом<mpi::request>, что позволяет запрашивать статус запроса связи (см. метод<test>) или ждать, пока он не будет завершен (см. метод<wait>). Несколько запросов могут быть выполнены одновременно с операцией<wait_all>.
Важное примечание: Стандарт MPI требует, чтобы пользователи сохраняли обработку запроса для неблокирующей связи и вызывали операцию «подождать» (или успешно тестировать для завершения) для завершения отправки или получения. В отличие от большинства реализаций C MPI, которые позволяют пользователю отклонить запрос на неблокирующую отправку, Boost. MPI требует, чтобы пользователь назвал «ожидание» или «тест», поскольку объект запроса может содержать временные буферы, которые должны храниться до завершения отправки. Более того, стандарт MPI не гарантирует, что приемник делает какой-либо прогресс перед вызовом «ждать» или «тестировать», хотя большинство реализаций C MPI позволяют приемникам прогрессировать перед вызовом «ждать» или «тестировать». С другой стороны, Boost.MPI обычно требует «тестирования» или «ожидания» звонков для достижения прогресса.
Если вы запускаете эту программу несколько раз, вы можете увидеть некоторые странные результаты, а именно:
Hello,world!
Другие будут производить:
world!Hello,
или даже какой-то искаженный вариант букв в «Привет» и «мир». Это указывает на некоторый параллелизм в программе, потому что после того, как оба сообщения (одновременно) передаются, оба процесса будут одновременно выполнять свои заявления печати. Как для производительности, так и для корректности неблокирующие операции связи имеют решающее значение для многих параллельных приложений с использованием MPI.
User-defined data types
Включение<boost/serialization/string.hpp>в предыдущие примеры очень важно: оно делает значения типа<std::string>сериализуемыми, чтобы их можно было передавать с помощью Boost. MPI. В целом, встроенные типы C++ (<int>s,<float>s, символы и т.д.) могут передаваться по MPI напрямую, в то время как пользовательские и библиотечные типы должны сначала быть сериализованы (упакованы) в формат, который поддается передаче. Повышаю. MPI опирается на библиотекуBoost.Serializationдля сериализации и десериализации типов данных.
Для типов, определенных стандартной библиотекой (например,<std::string>или<std::vector>) и некоторых типов в Boost (например,<boost::variant>), библиотекаBoost.Serializationуже содержит весь требуемый код сериализации. В этих случаях вам нужно только включить соответствующий заголовок из каталога<boost/serialization>.
Для типов, которые еще не имеют заголовка сериализации, сначала необходимо реализовать код сериализации, прежде чем типы могут быть переданы с помощью Boost. MPI. Рассмотрим простой класс<gps_position>, который содержит членов<degrees>,<minutes>и<seconds>. Этот класс становится сериализуемым, делая его другом<boost::serialization::access>и вводя шаблонную<serialize()>функцию следующим образом:
Полная информация о том, как сделать типы сериализуемыми, выходит за рамки этого учебника. Для получения дополнительной информации см.Boost.Serializationбиблиотечный учебник, из которого был извлечен приведенный выше пример. Одно из важных побочных преимуществ создания типов, сериализуемых для Boost. MPI заключается в том, что они становятся сериализуемыми для любого другого использования, такого как хранение объектов на диске и манипулирование ими в XML.
Некоторые сериализуемые типы, такие как<gps_position>выше, имеют фиксированное количество данных, хранящихся при фиксированных смещениях, и полностью определяются значениями их элемента данных (большинство POD без указателей являются хорошим примером). Если это так, поднимите. MPI может оптимизировать их сериализацию и передачу, избегая посторонних операций копирования. Чтобы обеспечить эту оптимизацию, пользователи должны специализироваться на признаке типа<is_mpi_datatype>, например:
Для типов без шаблонов мы определили макрос, чтобы упростить объявление типа как типа данных MPI.
BOOST_IS_MPI_DATATYPE(gps_position)
Для композитных признаков специализация<is_mpi_datatype>может зависеть от самого<is_mpi_datatype>. Например, объект<boost::array>фиксируется только тогда, когда фиксируется тип хранимого им параметра:
Оптимизация удаления избыточной копии может быть применена только тогда, когда форма типа данных полностью фиксирована. Типы с переменной длиной (например, строки, связанные списки) и типы, которые хранят указатели, не могут использовать оптимизацию, но увеличивают. MPI не сможет обнаружить эту ошибку во время компиляции. Попытка выполнить эту оптимизацию, когда она неверна, скорее всего, приведет к ошибкам сегментации и другому странному поведению программы.
Повышаю. MPI может передавать любой тип данных, определенный пользователем, из одного процесса в другой. Встроенные типы могут передаваться без каких-либо дополнительных усилий; определяемые библиотекой типы требуют включения заголовка сериализации; и определяемые пользователем типы потребуют добавления кода сериализации. Фиксированные типы данных могут быть оптимизированы для передачи с использованием признака типа<is_mpi_datatype>.
Операции «точка-точка»являются основными сообщениями, передающими примитивы в Boost. MPI. Однако многие приложения для передачи сообщений также требуют алгоритмов связи более высокого уровня, которые объединяют или обобщают данные, хранящиеся во многих различных процессах. Эти алгоритмы поддерживают множество общих задач, таких как «трансляция этого значения для всех процессов», «вычисление суммы значений на всех процессорах» или «нахождение глобального минимума».
Broadcast
Алгоритм<broadcast>на сегодняшний день является самой простой коллективной операцией. Он передает значение от одного процесса ко всем другим процессам в пределах 70. Например, следующая программа транслирует «Привет, мир!» от процесса 0 до любого другого процесса.<hello_world_broadcast.cpp>
Запуск этой программы с семью процессами даст такой результат, как:
Process #0 says Hello, World!
Process #2 says Hello, World!
Process #1 says Hello, World!
Process #4 says Hello, World!
Process #3 says Hello, World!
Process #5 says Hello, World!
Process #6 says Hello, World!
Gather
Коллектив<gather>собирает значения, производимые каждым процессом в коммуникаторе, в вектор значений на «корневом» процессе (определяется аргументом<gather>). Элемент /i/th в векторе будет соответствовать значению, собранному в процессе /i/th. Например, в следующей программе каждый процесс вычисляет свое собственное случайное число. Все эти случайные числа собираются в процессе 0 («корень» в данном случае), который распечатывает значения, соответствующие каждому процессору.<random_gather.cpp>
#include<boost/mpi.hpp>#include<iostream>#include<vector>#include<cstdlib>namespacempi=boost::mpi;intmain(){mpi::environmentenv;mpi::communicatorworld;std::srand(time(0)+world.rank());intmy_number=std::rand();if(world.rank()==0){std::vector<int>all_numbers;gather(world,my_number,all_numbers,0);for(intproc=0;proc<world.size();++proc)std::cout<<"Process #"<<proc<<" thought of "<<all_numbers[proc]<<std::endl;}else{gather(world,my_number,0);}return0;}
Выполнение этой программы с помощью семи процессов приведет к выходу, например: Хотя случайные значения будут меняться от одного прогона к следующему, порядок процессов на выходе останется прежним, потому что только процесс 0 записывает<std::cout>.
Process #0 thought of 332199874
Process #1 thought of 20145617
Process #2 thought of 1862420122
Process #3 thought of 480422940
Process #4 thought of 1253380219
Process #5 thought of 949458815
Process #6 thought of 650073868
Операция<gather>собирает значения из каждого процесса в вектор в одном процессе. Если вместо этого значения каждого процесса должны быть собраны в идентичные векторы на каждом процессе, используйте алгоритм<all_gather>, который семантически эквивалентен вызову<gather>, за которым следует<broadcast>полученного вектора.
Reduce
Коллектив<reduce>суммирует значения из каждого процесса в одно значение в заданном пользователем «корневом» процессе. Начало. Операция MPI<reduce>аналогична по духу операции STL.<accumulate>операция, поскольку она принимает последовательность значений (по одному на процесс) и объединяет их через объект функции. Например, мы можем произвольно генерировать значения в каждом процессе и вычислять минимальное значение по всем процессам с помощью вызова<reduce><random_min.cpp>:
#include<boost/mpi.hpp>#include<iostream>#include<cstdlib>namespacempi=boost::mpi;intmain(){mpi::environmentenv;mpi::communicatorworld;std::srand(time(0)+world.rank());intmy_number=std::rand();if(world.rank()==0){intminimum;reduce(world,my_number,minimum,mpi::minimum<int>(),0);std::cout<<"The minimum value is "<<minimum<<std::endl;}else{reduce(world,my_number,mpi::minimum<int>(),0);}return0;}
Использование<mpi::minimum<int>>указывает на то, что необходимо вычислить минимальное значение.<mpi::minimum<int>>— двоичный функциональный объект, который сравнивает свои два параметра через<<>и возвращает меньшее значение. Любая ассоциативная двоичная функция или объект функции будет работать. Например, для сопряжения строк с<reduce>можно использовать объект функции<std::plus<std::string>><string_cat.cpp>:
#include<boost/mpi.hpp>#include<iostream>#include<string>#include<functional>#include<boost/serialization/string.hpp>namespacempi=boost::mpi;intmain(){mpi::environmentenv;mpi::communicatorworld;std::stringnames[10]={"zero ","one ","two ","three ","four ","five ","six ","seven ","eight ","nine "};std::stringresult;reduce(world,world.rank()<10?names[world.rank()]:std::string("many "),result,std::plus<std::string>(),0);if(world.rank()==0)std::cout<<"The result is "<<result<<std::endl;return0;}
В этом примере мы вычисляем строку для каждого процесса, а затем выполняем сокращение, которое объединяет все строки в одну длинную строку. Выполнение этой программы с семью процессорами дает следующий выход:
The result is zero one two three four five six
Любой вид объектов двоичной функции может быть использован с<reduce>. Например, и таких объектов функций много в заголовке C++<<functional>>и Boost. Заголовок MPI<<boost/mpi/operations.hpp>>. Вы можете создать свой собственный объект. Функциональные объекты, используемые с<reduce>, должны быть ассоциативными, то есть<f(x,f(y,z))>должны быть эквивалентны<f(f(x,y),z)>. Если они также являются коммутативными (т.е.<f(x,y)==f(y,x)>), то они увеличиваются. MPI может использовать более эффективную реализацию<reduce>. Чтобы утверждать, что объект функции коммутативный, нужно будет специализировать класс<is_commutative>. Например, мы могли бы изменить предыдущий пример, сказав Boost. MPI, что конкатенация струн является коммутативной:
namespaceboost{namespacempi{template<>structis_commutative<std::plus<std::string>,std::string>:mpl::true_{};}}// end namespace boost::mpi
Добавляя этот код до<main()>, увеличить. MPI предполагает, что конкатенация строк является коммутативной и использует другой параллельный алгоритм для операции<reduce>. Используя этот алгоритм, программа выводит следующее при запуске с семью процессами:
The result is zero one four five six two three
Обратите внимание, что числа в результирующей строке находятся в другом порядке: это прямой результат Boost. MPI переупорядочение операций. Результат в этом случае отличался от некоммутативного результата, потому что конкатенация строк не коммутативна:<f("x","y")>не то же самое, что<f("y","x")>, потому что порядок аргументов имеет значение. Для действительно коммутативных операций (например, целочисленного сложения) более эффективный коммутативный алгоритм даст тот же результат, что и некоммутативный алгоритм. Повышаю. MPI также выполняет прямые отображения от объектов функций в<<functional>>до<MPI_Op>значениях, предварительно определенных MPI (например,<MPI_SUM>,<MPI_MAX>); если у вас есть собственные объекты функций, которые могут воспользоваться этим отображением, см. шаблон классов<is_mpi_op>.
Как и<gather>,<reduce>имеет вариант «все», называемый<all_reduce>, который выполняет операцию восстановления и передает результат во все процессы. Этот вариант полезен, например, при установлении глобальных минимальных или максимальных значений.
Следующий код<global_min.cpp>показывает вещательную версию примера<random_min.cpp>:
#include<boost/mpi.hpp>#include<iostream>#include<cstdlib>namespacempi=boost::mpi;intmain(intargc,char*argv[]){mpi::environmentenv(argc,argv);mpi::communicatorworld;std::srand(world.rank());intmy_number=std::rand();intminimum;all_reduce(world,my_number,minimum,mpi::minimum<int>());if(world.rank()==0){std::cout<<"The minimum value is "<<minimum<<std::endl;}return0;}
В этом примере мы предоставляем как входные, так и выходные значения, требующие в два раза больше места, что может быть проблемой в зависимости от размера передаваемых данных. Если нет необходимости сохранять входное значение, выходное значение может быть опущено. В этом случае входное значение будет переопределено с выходным значением и повышением. MPI способен в некоторых ситуациях реализовать операцию с более эффективным решением (используя флаг<MPI_IN_PLACE>отображения MPI C), как в следующем примере<in_place_global_min.cpp>:
#include<boost/mpi.hpp>#include<iostream>#include<cstdlib>namespacempi=boost::mpi;intmain(intargc,char*argv[]){mpi::environmentenv(argc,argv);mpi::communicatorworld;std::srand(world.rank());intmy_number=std::rand();all_reduce(world,my_number,mpi::minimum<int>());if(world.rank()==0){std::cout<<"The minimum value is "<<my_number<<std::endl;}return0;}
Managing communicators
Общение с Boost. MPI всегда происходит через коммуникатор. Коммуникатор содержит набор процессов, которые могут отправлять сообщения между собой и выполнять коллективные операции. В рамках одной программы может быть много коммуникаторов, каждый из которых содержит свое изолированное пространство связи, действующее независимо от других коммуникаторов.
При инициализации среды MPI доступен только «мировой» коммуникатор (названный<MPI_COMM_WORLD>в MPI C и связываниях Фортрана). «Мировой» коммуникатор, доступ к которому осуществляется посредством построения объекта по умолчанию<mpi::communicator>, содержит все процессы MPI, присутствующие при запуске программы. Другие коммуникаторы могут быть построены путем дублирования или построения подмножеств коммуникатора «мир». Например, в следующей программе мы разделили процессы на две группы: одна для процессов, генерирующих данные, а другая для процессов, которые будут собирать данные.<generate_collect.cpp>
Когда коммуникаторы разделены таким образом, их процессы сохраняют членство как в исходном коммуникаторе (который не изменяется расколом), так и в новом коммуникаторе. Однако ряды процессов могут отличаться от одного коммуникатора к другому, поскольку значения ранга в коммуникаторе всегда являются смежными значениями, начинающимися с нуля. Первые две трети процессов становятся «генераторами», а остальные — «коллекционерами». Разряды «коллекторов» в<world>коммуникаторе будут 2/3<world.size()>и выше, тогда как разряды тех же коллекторских процессов в<local>коммуникаторе начнутся с нуля. Следующий отрывок из<collect_data()>(в<generate_collect.cpp>) иллюстрирует, как управлять несколькими коммуникаторами:
mpi::statusmsg=world.probe();if(msg.tag()==msg_data_packet){// Receive the packet of datastd::vector<int>data;world.recv(msg.source(),msg.tag(),data);// Tell each of the collectors that we'll be broadcasting some datafor(intdest=1;dest<local.size();++dest)local.send(dest,msg_broadcast_data,msg.source());// Broadcast the actual data.broadcast(local,data,0);}
Код в этом за исключением выполняется "мастер" коллектор, например, узел с рангом 2/3<world.size()>в<world>коммуникатор и рангом 0 в<local>(коллектор) коммуникатор. Он получает сообщение от генератора через коммуникатор<world>, а затем передает сообщение каждому из коллекторов через коммуникатор<local>.
Для большего контроля при создании коммуникаторов для подгрупп процессов, Усиление. MPI<group>предоставляет возможности для вычисления союза<|>, пересечения<&>и разности<->двух групп, генерации произвольных подгрупп и т.д.
Separating structure from content
При передаче типов данных по MPI, которые не являются фундаментальными для MPI (например, строки, списки и типы данных, определяемые пользователем), увеличить. MPI должен сначала сериализовать эти типы данных в буфер, а затем передать их; приемник затем копирует результаты в буфер, прежде чем десериализировать в объект на другом конце. Для некоторых типов данных эти накладные расходы могут быть устранены с помощью<is_mpi_datatype>. Однако типы данных переменной длины, такие как строки и списки, не могут быть типами данных MPI.
Повышаю. MPI поддерживает второй метод повышения производительности путем отделения структуры этих структур данных переменной длины от содержимого, хранящегося в структурах данных. Эта функция полезна только тогда, когда форма структуры данных остается прежней, но содержание структуры данных должно быть сообщено несколько раз. Например, при анализе конечных элементов структура сетки может быть зафиксирована в начале вычисления, но различные переменные на ячейках сетки (температура, напряжение и т.д.) будут сообщаться много раз в процессе итеративного анализа. В данном случае – рост. MPI позволяет сначала отправить «скелет» сетки один раз, затем передать «контент» несколько раз. Поскольку содержание не должно содержать никакой информации о структуре типа данных, оно может передаваться без создания отдельных буферов связи.
Чтобы проиллюстрировать использование скелетов и контента, мы возьмем несколько более ограниченный пример, в котором мастер-процесс генерирует случайные последовательности чисел в список и передает их нескольким рабским процессам. Длина списка будет фиксирована при запуске программы, поэтому содержание списка (т.е. текущая последовательность чисел) может быть эффективно передано. Полный пример приведен в<example/random_content.cpp>. Мы находимся в процессе мастера (ранг 0), который строит список, передает его структуру через<skeleton>, а затем неоднократно генерирует случайные последовательности чисел, которые будут транслироваться на процессы раба через<content>:
// Generate the list and broadcast its structurestd::list<int>l(list_len);broadcast(world,mpi::skeleton(l),0);// Generate content several times and broadcast out that contentmpi::contentc=mpi::get_content(l);for(inti=0;i<iterations;++i){// Generate new random valuesstd::generate(l.begin(),l.end(),&random);// Broadcast the new content of lbroadcast(world,c,0);}// Notify the slaves that we're done by sending all zeroesstd::fill(l.begin(),l.end(),0);broadcast(world,c,0);
Рабские процессы имеют очень похожую структуру с хозяином. Они получают (по вызову<broadcast()>) скелет структуры данных, а затем используют его для построения собственных списков целых чисел. В каждой итерации они получают через другой<broadcast()>новый контент в структуре данных и вычисляют некоторое свойство данных:
// Receive the content and build up our own liststd::list<int>l;broadcast(world,mpi::skeleton(l),0);mpi::contentc=mpi::get_content(l);inti=0;do{broadcast(world,c,0);if(std::find_if(l.begin(),l.end(),std::bind1st(std::not_equal_to<int>(),0))==l.end())break;// Compute some property of the data.++i;}while(true);
Скелеты и содержимое любого типа данных Serializable могут передаваться либо через<send>и<recv>членов класса<communicator>(для точечных коммуникаторов), либо транслироваться через<broadcast()>коллектив. При разделении структуры данных на скелет и содержимое будьте осторожны, чтобы не изменять структуру данных (либо на стороне отправителя, либо на стороне получателя), не передавая скелет снова. Повышаю. MPI не может обнаружить эти случайные изменения структуры данных, которые, вероятно, приведут к неправильной передаче данных или нестабильным программам.
Для получения оптимальной производительности для малых типов данных фиксированной длины, не содержащих каких-либо указателей, очень важно отметить их с помощью признаков типа Boost. MPI и Boost.Serialization.
Уже обсуждалось, что фиксированные типы длины, не содержащие указателей, могут использоваться в качестве<is_mpi_datatype>, например:
Кроме того, это может дать существенный прирост производительности, чтобы отключить отслеживание и версию для этих типов, если не используются указатели на эти типы, используя классы признаков или вспомогательные макросы Boost. Сериализация:
Дополнительные оптимизации возможны на однородных машинах, избегая вызовов MPI_Pack/MPI_Unpack, но используя прямую битовую копию. Эта функция включена по умолчанию путем определения макроса<BOOST_MPI_HOMOGENEOUS>в файле включения<boost/mpi/config.hpp>. Это определение должно быть последовательным при строительстве. MPI и при создании приложения.
Кроме того, все классы должны быть помечены как is_mpi_datatype, так и as is_bitwise_serializable с помощью вспомогательного макроса Boost. Сериализация:
BOOST_IS_BITWISE_SERIALIZABLE(gps_position)
Обычно безопасно сериализовать класс, для которого является_mpi_datatype, используя двоичную копию битов. Исключение составляют классы, для которых некоторые члены должны быть пропущены для сериализации.
Mapping from C MPI to Boost.MPI
В этом разделе представлены таблицы, которые отображают функции и константы стандартного C MPI до их увеличения. эквиваленты MPI. Он будет наиболее полезен для пользователей, которые уже знакомы с интерфейсами C или Fortran для MPI, или для переноса существующих параллельных программ на Boost. MPI.
Повышаю. MPI автоматически отображает типы данных C и C++ на их эквиваленты MPI. Следующая таблица иллюстрирует отображения между типами C++ и константами типа данных MPI.
<unsignedlonglongint>, если поддерживается компилятором
<MPI_FLOAT_INT>
<std::pair<float,int>>
<MPI_DOUBLE_INT>
<std::pair<double,int>>
<MPI_LONG_INT>
<std::pair<long,int>>
<MPI_2INT>
<std::pair<int,int>>
<MPI_SHORT_INT>
<std::pair<short,int>>
<MPI_LONG_DOUBLE_INT>
<std::pair<longdouble,int>>
Повышаю. MPI не предоставляет прямые обертки для функциональности MPI-производных типов данных. Вместо этого, буст. MPI опирается на библиотекуBoost.Serializationдля построения типов данных MPI для классов, определенных пользователем. В разделе отипах данных, определяемых пользователем, описан этот механизм, который используется для типов, помеченных как «типы данных MPI» с использованием<is_mpi_datatype>.
Приведенная ниже таблица типов данных описывает, какие типы C++ соответствуют функциональности конструктора типов данных C MPI. Повышаю. MPI может фактически не использовать функцию C MPI, указанную при построении типов данных определенной формы. Так как фактические типы данных построены Boost. MPI обычно скрыты от пользователя, многие из этих операций называются внутри Boost. MPI.
Средства упаковки MPI хранят значения в смежный буфер, который позже может быть передан через MPI и распакован в отдельные значения через средства распаковки MPI. Как и в случае с типом данных, Boost. MPI обеспечивает абстрактный интерфейс к средствам упаковки и распаковки MPI. В частности, два класса архивов<packed_oarchive>и<packed_iarchive>могут использоваться для упаковки или распаковки смежного буфера с использованием средств MPI.
Повышаю. MPI поддерживает индивидуальное отображение для большинства коллективов MPI. Для каждого коллектива, предоставленного Boost. MPI, базовый коллектив C MPI будет использоваться, когда это возможно (и эффективно).
Повышаю. MPI использует функциональные объекты, чтобы указать, как должны происходить сокращения в его эквивалентах<MPI_Allreduce>,<MPI_Reduce>и<MPI_Scan>. В следующей таблице показано, какпредопределенныеипользовательские операции сокращениямогут быть отображены между C MPI и Boost. MPI.
MPI определяет несколько специальных коммуникаторов, включая<MPI_COMM_WORLD>(включая все процессы, с которыми может связываться локальный процесс),<MPI_COMM_SELF>(включая только локальный процесс) и<MPI_COMM_EMPTY>(включая отсутствие процессов). Все эти специальные коммуникаторы являются экземплярами класса<communicator>в Boost. MPI.
Повышаю. MPI обеспечит полную поддержку для создания коммуникаторов с различными топологиями и последующего запроса этих топологий. Поддержка топологий графов обеспечивается через интерфейс кBoost Graph Library (BGL), где может быть создан коммуникатор, который соответствует структуре любого графа BGL, а топология графов коммуникатора может рассматриваться как граф BGL для использования в существующих общих алгоритмах графов.
Статья Tutorial раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 24. Boost.MPI может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.