Теория
Начнем с начала
Первое время не было единого стандарта (API) для параллельных вычислений и программистам приходилось писать для каждого кластера архитектурно-специфический код. Но, как известно, программисты люди рациональные и быстро было решено организовать стандарты (самые известные — MPI, OpenMP).
MPI — Message Passing Interface. Это специфический API, который реализуют производители кластеров для того, чтобы можно было легко переносить программы с кластера на кластер не изменяя ни байта исходного кода(!).
Параллельная программа должна эффективно использовать вычислительные мощности и коммуникационную среду. В MPI вся работа по распределению нагрузки на узлы и сеть ложатся на программиста и для максимальной производительности необходимо знать особенности конкретного кластера. MPI очень элегантно решает вопрос топологии сети: имеются понятия коммуникаторов — группы процессов, которые можно пронумеровать в соответствии с топологией сети (для этого используется функция MPI_Cart_create, которая позволяет задать любую топологию от решётки до гиперкуба).
Целесообразность распараллеливания
Некоторые примеры в учебных пособиях весьма синтетические — в них считается какой-нибудь ряд в пределах стандартного типа (например, double), что на практике вычисляется за время много меньшее того, которое тратится на инициализацию и передачу чего-либо по сети (вычисление числа pi в double на двух компьютерах с Gigabit Ethernet примерно в два раза медленнее вычисления на одном компьютере). Однако, MPI позволяет использовать многоядерные процессоры (что почему-то многие забывают), а между ядрами скорость передачи совершенно другого порядка, поэтому всегда нужно знать архитектуру и топологию системы.
Практика
Про теорию можно много писать, но лучше постигать теорию соразмерно с практикой.
Для начала установим какую-нибудь реализацию MPI на свой компьютер. Одной из самых распространённых реализаций MPI является MPICH (MPI Chameleon).
Установка
В убунте устанавливается в одну строчку:
sudo apt-get install mpich2Напишем простенькую программку, которая ничего полезного не делает:
#include <stdio.h>
#include <mpi.h>
int main (int argc, char* argv[])
{
int errCode;
if ((errCode = MPI_Init(&argc, &argv)) != 0)
{
return errCode;
}
int myRank;
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
if (myRank == 0)
{
printf("It works!\n");
}
MPI_Finalize();
return 0;
}
* This source code was highlighted with Source Code Highlighter.
Скомпилируем эту программку:
mpicc -o test.bin ./test.cПопробуем запустить:
mpirun ./test.binИ (если еще не настроили демон mpd) получим сообщение о том, что демон mpd не запущен.
mpiexec: cannot connect to local mpd (/tmp/mpd2.console_valery); possible causes:
1. no mpd is running on this host
2. an mpd is running but was started without a "console" (-n option)
In case 1, you can start an mpd on this host with:
mpd &
and you will be able to run jobs just on this host.
For more details on starting mpds on a set of hosts, see
the MPICH2 Installation Guide.
При попытке запустить mpd будет сказано об отсутствии настроек (почему, собственно, не запускается демон)
configuration file /home/valery/.mpd.conf not found
A file named .mpd.conf file must be present in the user's home
directory (/etc/mpd.conf if root) with read and write access
only for the user, and must contain at least a line with:
MPD_SECRETWORD=<secretword>
One way to safely create this file is to do the following:
cd $HOME
touch .mpd.conf
chmod 600 .mpd.conf
and then use an editor to insert a line like
MPD_SECRETWORD=mr45-j9z
into the file. (Of course use some other secret word than mr45-j9z.)
Секретное слово нужно только для подключения узлов. Если мы будем подключать ещё компьютеры, то надо будет и на них ставить MPICH и надо будет занести узел в список узлов, а также не будет лишним настроить подключение по ssh с использованием ключей (для общения с узлами).
Если всё сделано правильно, то получим примерно такой вывод:
$ mpirun ./test.bin
It works!MPI_Init — обязательна для вызова, так как выполняет инициализацию библиотеки MPI.
MPI_COMM_WORLD — идентификатор глобального коммуникатора, содержащего все процессы.
MPI_Comm_rank — возвращает идентификатор (номер, ранг) процесса в рамках заданного коммуникатора.
Почему выводим на экран только при ранге, равном 0? Просто этот процесс как раз соответствует по умолчанию тому, который имеет доступ к консоли того терминала, с которого производился запуск. Мы можем использовать и любой другой, но так просто удобнее.
Вместо вывода
Можно написать параллельную программу не имея почти никаких знаний о параллельном программировании, но написание эффективных программ является трудоёмким процессом выбора алгоритма и его реализации, подгонки под систему и так далее. Но если начать писать простенькие программки и при этом читать спецификации и литературу о вычислительных системах (об их архитектуре, коммуникационных средах и прочем), то со временем, %username%, будешь способен подчинить себе даже такие страшные машины как те, которые представлены в списке топ-500
Комментариев нет:
Отправить комментарий