Автор: Пользователь скрыл имя, 16 Марта 2012 в 11:58, реферат
Параллельное программирование служит для создания программ, эффективно использующих вычислительные ресурсы за счет одновременного исполнения кода на нескольких вычислительных узлах. Для создания параллельных приложений используются параллельные языки программирования и специализированные системы поддержки параллельного программирования, такие как MPI и OpenMP. Параллельное программирование является более сложным по сравнению с последовательным как в написании кода, так и в его отладки. Для облегчения процесса параллельного программирования существуют специализированные инструменты, например, отладчик TotalView, статический анализатор кода VivaMP.
1.Теория параллельного программирования………………………………………………2
2.Open MP. Что это такое?.................................................................................6
3. Проблемы параллельного программирования………………………………………..9
4. Интерфейс MPI…………………………………………………………………………………………..12
5.Выводы………………………………………………………………………………………………………..14
Проблемы
параллельного
В сущности,
главная трудность при
Грабли первые, самые простые и очевидные, - это необходимость балансировки загрузки потоков. Скажем, если один поток считает физику, другой - AI, а третий выводит на экран текущую сцену, то вполне возможно, что первые два потока управятся со своими делами гораздо раньше третьего[В играх со сложной графикой так обычно и происходит - "графическая" подсистема тормозит все остальное] и будут вынуждены его дожидаться. И если вычисления в первом потоке составляют 90% общего объема работы, а во втором - 10%, то больше чем 11-процентного увеличения производительности мы от программы не дождемся.
Замечание из
этой же серии: если 80% программного кода
поддаются распараллеливанию, а 20% -
нет, то получить больше 40% прироста производительности
от добавления второго ядра (равно
как и более чем пятикратный
выигрыш при любом числе
Грабли вторые
- существование разделяемых
Поэтому для защиты разделяемых между несколькими потоками переменных в параллельных программах вводятся специальные объекты синхронизации, которые позволяют заблокировать изменение того или иного объекта двумя потоками одновременно. Делается это примерно так: объект[Объект синхронизации, но вместе с ним - и весь объект (тот же наш игровой танк, например), который этот объект синхронизации защищает] отдается какому-то одному конкретному потоку, а другие желающие получить объект в пользование ставятся в очередь и ждут, пока нужный объект не освободится. Программисты, забывающие это сделать, как раз и наступают на те самые вторые грабли, обладающие пренеприятным свойством незаметно ломать программу. И ломать так, что она обрушивается не в момент "поломки", а минуты через три, когда "сомнительное место" давным-давно затерялось в пучинах кода, причем происходит это каждый раз в новом месте и в новое время.
Грабли третьи: если недостаточное количество объектов синхронизации - зло, ибо программист рискует заполучить время от времени глючащую программу, то переизбыток этих объектов - жуткие вериги на шее проекта. Пусть, скажем, практически любой из наших объектов может изменять игровую землю и стремится получить ее для себя. Поскольку принадлежать двум объектам одновременно земля не сможет, то находится она в каждый момент времени только у одного объекта. Который и будет обрабатываться, а всем остальным потокам придется терпеливо ожидать своей очереди. Получится вот такая картинка (рис. 3), где параллельными вычислениями и не пахнет. С этим успешно борются, беря блокировку ровно на то время, пока она действительно необходима (прочитать состояние земли, проверить его и записать новое состояние), но тогда возникают новые грабли - дедлоки. Предположим, что мы угодили снарядом в землю совсем рядышком от стоящего на ней танка. Пострадала и земля, и танк. Программа добросовестно определяет, что, где и как требуется изменить (поменять рельеф земли и изменить "жизни" у танка), берет первый объект синхронизации "на землю", тянется ко второму объекту синхронизации "на танк"… и тут же виснет. В чем дело? Оказывается, этот танк ждет, когда освободится земля, чтобы внести в нее свои изменения. И пока он земли не дождется, он не отдаст блокировку на самого себя, которая нужна потоку, который "держит" блокировку на ту самую землю. Считаете, что подобный дедлок - надуманная штука? Значит, вы никогда не занимались параллельным программированием: подобные ситуации здесь возникают если не на каждом шагу, то, по крайней мере, очень часто. Еще одна ситуация того же рода - один из потоков взял блокировку на что-то, но забыл освободить, а сторонний поток некстати решил это что-то проверить. Отсюда вытекает второе золотое правило "параллельного" программиста - никогда не пытаться обладать двумя объектами одновременно и тщательно проверять, что все однажды взятые объекты своевременно освобождаются.
Неплохой джентльменский набор, не правда ли? А сколько занятных вопросов связано с работой в "параллельном" режиме стандартных библиотек! К примеру, функция GetHostByAddr в стандартном программном интерфейсе Microsoft, активно использующаяся сетевыми программами, одно время грешила тем, что при ее повторных вызовах с разными адресами из разных потоков выдавала обоим потокам указатель на одну и ту же структуру данных, хотя запрашивали они совсем разное. И если производитель клятвенно заверяет вас, что его библиотека совсем-совсем, ну честно-честно является thread-safe[Безопасной для использования в параллельном режиме], - вспомните, что даже Microsoft нет-нет да и ошибается, модифицируя продукт с десятилетней историей. А о трудности отыскания подобных глюков красноречиво свидетельствует то, сколько потребовалось времени, чтобы GetHostByAddr выловить[Исправили его в Windows XP SP1. Сколько лет он жил никем не замеченный, одному богу известно].
Интерфейс MPI.
Еще один стандарт де-факто в мире параллельных вычислений - пакет MPI (Message Passing Interface), тоже разрабатывавшийся как универсальное средство облегчения жизни разработчику параллельного ПО. Только устроено оно совсем иначе, нежели OpenMP, и ориентировано в основном для других, "более возвышенных" целей.
Идея MPI заключается в следующем. OpenMP (да и многие другие системы для разработки параллельного ПО) ориентируется на так называемые системы с общей памятью, когда на компьютере запущена всего одна программа (точнее, один процесс), но внутри этого процесса "живет" несколько потоков исполнения, каждому из которых доступна вся память процесса, а стало быть, и все его данные. MPI исходит из другой предпосылки: на компьютере запущено много-много программ (процессов), которые друг с другом напрямую общаться не могут и вынуждены устанавливать контакт через специальные окна или даже внешние каналы связи. Называется все это IPC (Inter-Process Communication) и, как вы уже, наверное, догадались, сильно изменяется от компьютера к компьютеру и от операционной системе к операционной системе. А MPI - попытка стандартизировать связь между процессами, предоставив всем желающим удобную модель запуска на нескольких процессорах тех программ, которые будут коллективно обрабатывать данные, и обеспечивая "почтовые пересылки" между этими программами. Вот и весь Message Passing Interface.
MPI универсален
и всеяден. Он не накладывает
практически никаких
Впрочем, при желании можно использовать MPI и для обычных двухъядерных процессоров или двухпроцессорных систем - "вотчины" проектов OpenMP. Но, конечно, MPI для таких целей "тяжеловат", - как в плане быстроты исполнения программного кода, которому, в отличие от его OMP-коллег, приходится еще и оплачивать "накладные расходы" на канал связи, так и в плане высокой сложности разработки MPI-приложений. Последние, правда, лишены большинства тех "граблей", которые существуют для обычных систем с распределенной памятью; но зато для написания соответствующего кода от программиста требуется четкое мышление, позволяющее в деталях продумать систему обмена информацией между процессами.
Отладка параллельных приложений
Не говоря даже о том, что когда в программе запущен не один, а несколько потоков, то пошаговая отладка превращается в настоящий кошмар: контрольные точки "ловят" все треды подряд, а шаг одного потока запросто может сопровождаться полусотней шагов соседнего. Главная проблема в отладке параллельных приложений заключается в том, что возникающие там неполадки уникальны. Зачастую они связаны со случайным совпадением каких-то событий в "жизни" слабо связанных друг с другом потоков, а потому проявляются, как говорится, в соответствии с текущей фазой луны, - возникнут раз-другой и бесследно исчезнут. Мало того, иногда присутствие "наблюдателя" (отладочных средств) изменяет результат измерений, поскольку слегка перестраивает "свойства окружающей среды", - вот и вылавливай после этого какой-нибудь плавающий глюк, обусловленный параллельностью.
Возможных решений тут всего три. Во-первых, средства, подобные OpenMP, заметно упрощают разработку "параллельных" программ, поскольку устраняют необходимость ручного задания объектов синхронизации. Правда, платить за это приходится еще более суженной функциональностью и производительностью (автоматика особой сообразительностью не отличается), так что изучить объекты синхронизации программисту не помешает. Второй способ - использование "по старинке" большого объема выводимой вручную отладочной информации. И, наконец, третий - использование специальных программ вроде Intel Thread Checker, не только наглядно и доступно отображающих в виде графика ход исполнения программы, но и способных в некоторых случаях находить распространенные ошибки начинающих.
Выводы.
Как ни крути, за параллельными приложениями будущее, - а значит, пришла пора осваивать соответствующие приемы программирования и инструментарий. Компания Intel не только обещает завалить рынок недорогими многоядерными процессорами, но и предоставляет весь необходимый инструментарий для полноценного использования своих разработок. И судя по тому, что новейшие продукты Intel на процессорах AMD зачастую отказываются запускаться - AMD как платформе разработчиков вскоре придется неуютно.
Список литературы: