Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Методы использования PVM-задач






 

Работу, которую выполняет С++-программа, можно распределить между функциями, объектами или их сочетаниями. Действия, выполняемые программой, обычно делятся на такие логические категории: операции ввода-вывода, интерфейс пользователя, обработка базы данных, обработка сигналов и ошибок, числовые вычисления и т.д. Отделяя код интерфейса пользователя от кода обработки файлов, а также код процедур печати от кода числовых вычислений, мы не только распределяем работу програ м мы между функциями или объектами, но и стараемся выделять категории действий в соответствии с их характером. Логические группы организуются в библиотеки, модули, объектные шаблоны, компоненты и оболочки. Такой тип организации мы поддерживае м и при внесении PVM-задач в С++-програ мм у. Мы може м подойти к деко м позиции работ (work breakdown structure), используя м етод либо восходя щ его, либо нисходя щ его проектирования. В любом случае параллелиз м должен естественно вписываться в работу, которая на м ечена для выполнения функцией, модулем или объектом.

Не самая удачная идея — попытаться директивно навязать параллелиз м програ мм е. Искусственно насаждае м ый параллелиз м является причиной фор м ирования гро м оздкой архитектуры, которая, как правило, трудна для пони м ания и поддержки и создает сложности при определении корректности програ мм ы. Поэто м у, если програ мм а использует PVM-задачи, они должны быть результато м естественного разбиения программы. Каждую PVM-задачу следует отнести к одной из функциональных категорий. Например, если м ы разрабатывае м приложение, которое содержит обработку данных на естественном языке (Natural Language Processing — NLP), м еханиз м речевого воспроизведения текста (text-to-speech engine — TTS-engine) как часть интерфейса пользователя и формирование логических выводов как часть выборки данных, то параллелизм (естественный для NLP-компонента) должен быть представлен в виде задач внутри NLP-модуля или объекта, который отвечает за NLP-обработку. Аналогично параллелизм внутри компонента фор м ирования логических выводов следует представить в виде задач, составляю щ их модуль (объект или оболочку) выборки данных, отвечаю щ ий за выборку данных. Другими словами, мы идентифицируем PVM-задачи там, где они логически вписываются в работу, выполняемую программой, а не просто разбиваем работу программы на набор некоторых об щ их PVM-задач.

Соблюдение первичности логики и вторичности параллелизма имеет несколько последствий для С++-программ. Это означает, что мы могли бы порождать PVM-задачи из функции main () или из функций, вызываемых из функции main () (и даже из других функций). Мы могли бы порождать PVM-задачи из методов, прина д лежащих объектам. Место порождения задач зависит от требований к параллельности, выдвигаемых соответствую щ ей функцией, модулем или объектом. В об щ ем случае PVM-задачи можно разделить на две категории: SPMD (производная от SIMD) и MPMD (производная от MIMD). В модели SPMD все задачи будут выполнять одинаковый набор инструкций, но на различных наборах данных. В модели MPMD все задачи будут выполнять различные наборы инструкций на различных наборах данных. Но какую бы модель мы не использовали (SPMD или MPMD), создание задач должно происходить в соответствую щ их областях программы. Некоторые возможные конфигурации для порождения PVM-задач показаны на рис. 6.4.

 

Реализация модели SPMD (SIMD) c помощью PVM-и С++-средств

 

Вариант 1 на рис. 6.4 представляет ситуацию, при которой функция main () порождает от 1 до N задач, причем каждая задача выполняет один и тот же набор инструкций, но на различных наборах данных. Су щ ествует несколько вариантов реализации этого сценария. В листинге 6.1 показана функция main (), которая вызывает функцию pvm_spawn().

// Листинг б.1. Вызов функции pvm_spawn() из // функции main()

int main(int argc, char *argv[]) {

int TaskId[10]; int TaskId2[5]; // 1-е порождение:

pvm_spawn(«set_combination», NULL, 0, " ", 10, TaskId);

// 2-е порождение:

pvm_spawn(«set_combination», argv, 0, " ", 5, TaskId2); //...

}

В листинге 6.1 при первом порождении создается 10 задач. Каждал задача будет выполнять один и тот же набор инструкций, содержа щ ихся в программе set_combination. При успешном выполнении функции pvm_spawn () массив TaskId будет содержать идентификаторы PVM-задач. Если про г ра мм а в листин г еб.1 имеет идентификатор TaskIds, то она может использовать функции pvm_send() для отправки данных, под г отовленных д л я обработки каждой про г раммой. Это воз м ожно б л а г одаря то м у, что функция pvm_send () содержит идентификатор задачи-получате л я.

 

  Рис. 6.4. Некоторые возможные конфигурации для порождения PVM-задач

 

При второ м порождении (с м. листин г б.1) создается пять задач, но в это м случае каждой задаче с по м о щ ью пара м етра argv передается необходи м ал информация. Это — дополнительный способ передачи информации задачам при их запуске. Тем самы м сыновние задачи получают е щ е одну воз м ожность уникальны м образо м идентифицировать себя с по м о щ ью значений, получае м ых в пара м етре argv. В листин г е 6 .2, чтобы создать N задач, функция main () несколько раз (вместо одно г о) обра щ ается к функции pvm_spawn ().

// Листинг 6.2. Использование нескольких вызовов

// функции pvm_spawn() из функции main()

int main(int argc, char *argv[]) {

int Taskl; int Task2; int Task3; //...

pvm_spawn(«set_combination», NULL, 1, «hostl», l, & Taskl); pvm_spawn(«sec_combination», argv, 1, «host2», 1, & Task2); pvm_spawn(«set_combination», argv++, l, «host3», l, & Task3); //...

}

Подход к созданию задач, продемонстрированный в листин г е 6.2, можно использовать в том случае, ко г да нужно, чтобы задачи выполнялись на конкретных компьютерах. В этом состоит одно из достоинств PVM-среды. Ведь про г рамме ино г да стоит воспользоваться преимуществами некоторых конкретных ресурсов конкретно г о компьютера, например, специальным математическим спецпроцессором, процессором графическо г о устройства вывода или какими-то дру г ими возможностями. В листин г е 6.2 обратите внимание на то, что каждый компьютер выпол н яет один и тот же набор инструкций, но все они получили при этом разные ар г ументы командной строки. Вариант 2 (см. рис. 6.4) представляет сценарий, в котором функция main() не порождает PVM-задачи. В этом сценарии PVM-задачи ло г ически связаны с функцией funcB (), и поэтому здесь именно функция funcB () порождает PVM-задачи. Функциям main() и funcA() нет необходимости знать что-либо о PVM-задачах, поэтому им и не нужно иметь соответствую щ ий PVM-код. Вариант 3 (см. рис. 6.4) представл я ет сценарий, в котором функции main () и дру г им функциям в про г рамме прису щ естественный параллелизм. В этом случае роль «дру г их» функций и г рает функция funcA (). PVM-задачи, порождаемые функциями main () и funcA (), выполняют различный код. Несмотря на то что задачи, порожденные функцией main (), выпол н яют идентичный код, и задачи, порожденные функцией funcA (), выполняют идентичный код, эти два набора задач совершенно различны. Этот вариант иллюстрирует возможность C++-про г раммы использовать коллекции задач для о д новременно г о решения различных проблем. Ве д ь не су щ ествует причины, по которой на про г рамму бы нала г алось о г раничение решать в любой момент времени только о д ну проблему. Вариант 4 (см. рис. 6 .4) пре д ставляет случай, ко гд а параллелизм заключен внутри объекта, поэтому порождение PVM-задач реализует один из методов это г о объекта. Этот вариант показывает, что при необхо д имости параллелизм может исходить из класса, а не из «свободной» функции.

Как и в дру г их вариантах, все PVM-задачи, порожден н ые в варианте 4, выполняют одинаковый набор инструкций, но с различными данны м и. Этот SPMD етод (Single Program, Multiple-Data — одна програ м ма, множество потоков данных) часто используется для реализации параллельного решения проблем некоторого типа. И то, что язык С++ обладает по д держкой объектов и средств обоб щ енного программирования на основе шаблонов, делает его основным инстру м енто м при решении подобных задач. Объекты и шаблоны позволяют С++-программисту представлять обоб щ енные игибкие решения для различных проблем с помо щ ью одной-единственной программной единицы. Наличие единой программной единицы прекрасно вписывается в модель параллелиз м а SPMD. Понятие класса расширяет модель SPMD, позволяя решать целый класс пробле м. Шаблоны дают воз м ожность решать определенный класс проблем для практически любого типа данных. Поэтому, хотя все задачи в модели SPMD выполняют один и тот же код (програ мм ную единицу), он м ожет быть предназначен для любого объекта или л юбого из его пото м ков и рассчитан на раз л ичные типы данных (азначит, и на различные объекты!). Напри м ер, в листингеб.З используется четыре PVM-задачи для генерирования четырех множеств, в каждом из которых имеется C(n, r) элементов: C(24, 9), C(24, 12), C(7, 4) и C(7, 3). В частности, влистинге 6.3 перечисляются возможные сочетания из 24 цветов, взятые по 9 и по 12. Здесь также перечисляются возможные сочетания из 7 чисел с плаваю щ ей точкой, взятые по 4 и по 3. Пояснения пообозначению C(n, r) приведены в разделе $ 6.1 («Обозначение сочетаний»).

// Листинг б.З. Создание сочетаний из заданных множеств

int main(int argc, char *argv[]) {

int RetCode, TaskId[4];

RetCode = pvm_spawn («pvm_generic_combination11, NULL, 0, " ", 4, TaskId);

if(RetCode == 4) {

colorCombinations (TaskId[0], 9); colorCombinations(TaskId[l], 12); numericCombinations(TaskId[2], 4); numericCombinations(TaskId[3], 3); saveResult(TaskId[0]); saveResult(TaskId[l]); saveResult(TaskId[2]); saveResult(TaskId[3]); pvm_exit();

}

else{

cerr ««Ошибка при порождении сыновнего процесса.»

«endl; pvm_exit();

}

return(0);

}

В листинге 6.3 обратите внимание на порождение четырех PVM-задач: pvm_spawn(«pvm_generic_combination», NULL, 0, н », 4, TaskId);

Каждая порожденнал задача должна выполнять програ м му с именем pvm _generic_combination. Аргу м ент NULL в вызове функции pvm_spawn() означает, что через параметр argv[] не передаются никакие опции. Значение 0 в вызове функции pvm_spawn () свидетельствует, что нас не беспокоит, на каком ко м пьютере будет выполняться наша задача. Аргу м ент TaskId представляет м ассив, предназначенный для хранения четырех целочисленных значений, который при условии успешного выполнения функции pvm_spawn () будет содержать идентификаторы каждой порожденной PVM-задачи. В листингеб.З обратите также вни м ание на вызов функций colorCombinations () и numericCombinations (). Они «дают работу» PVM-задачам. Определение функции colorCombinations () представлено в листинге 6.4.

// Листинг 6.4. Определение функции colorCombinations()

void colorCombinations(int TaskId, int Choices) {

int MessageId =1; char *Buffer; int Size; int N;

string Source(«blue purple green red yellow orange

silver gray "); Source.append(«pink black white brown light_green

aqua beige cyan "); Source.append(«olive azure magenta plum orchid violet

maroon lavender»); Source. append (" \n**);

Buffer = new char[(Source.size() + 100)]; strcpy(Buffer, Source.c_str()); N = pvm_initsend(PvmDataDefault); pvm_pkint(& Choices, 1, 1); pvm_send(TaskId, MessageId); N = pvm_initsend(PvmDataDefault); pvm_pkbyte(Buffer, strlen(Buffer), 1); pvm_send(TaskId, MessageId); delete Buffer;

}

В листингеб.З от м етьте два обращения к функции colorCombinations(). Каждое из них велит PVM-задаче перечислить различное количество сочетаний цветов: C(24, 9) и C(24, 12). Первал PVM-задача д олжна сгенерировать 1 307 504 цветовых сочетаний, а вторал — 2 704 156. Эту работу выполняет програм м а, заданнал в вызове функции pvm_spawn (). Каждый цвет представляется строкой. Следовательно, програ мм а pvm_generic_combination (с по м ощью функции colorCombinations()) генерирует сочетания цветов, используя в качестве входных данных набор строк. Но когда она орулует «рука м и» функции numericCombinations (), показанной в листинге 6.5, в качестве входных данных используется набор чисел с плавающей точкой. Код листинга 6.3 также содержит два вызова функции numericCombinations (). Первый генерирует C(7, 4) сочетаний, а второй — C(7, 3).

// Листинг 6.5. Использование PVM-задач для генерирования // сочетаний чисел

void numericCombinations(int TaskId, int Choices) {

int MessageId = 2; int N;

double ImportantNumbers[7] =

{3.00e+8, 6.67e-ll, 1.99e+30,

6.2. Библио т ека PVM для языка С++ 229

1.67e-27, 6.023e+23, 6.63e-34,

3.14159265359}; N = pvm_initsend(PvmDataDefault); pvm_pkint(& Choices, 1, 1); pvm_send(TaskId, MessageId); N = pvm_initsend(PvmDataDefault); pvm_pkdouble (ImportantNumbers, 5, 1); pvm_send(TaskId, MessageId);

}

В функции numericCombinations () из листинга 6.4 PVM-задача использует м ассив чисел с плаваю щ ей точкой, а не м ассив байтов, представл я ю щ их строки. Поэто м у функция colorCombinations() отправл я ет свои данные PVM-задача м с по м о щ ью вызовов таких функций:






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.