Научная статья на тему 'О направлениях развития дисциплины параллельного программирования'

О направлениях развития дисциплины параллельного программирования Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
111
21
i Надоели баннеры? Вы всегда можете отключить рекламу.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Федотов Илья Евгеньевич

Рассмотрена проблема текущего состояния дисциплины параллельного программирования в сфере образования. Приведены аргументы в пользу включения в образовательный процесс описания высокоуровневых моделей параллельного программирования с возможностью их реализации. Приведено несколько примеров высокоуровневых моделей, позволяющих организацию параллельных программ и предлагаемых для рассмотрения в процессе преподавания параллельного и распределенного программирования.

i Надоели баннеры? Вы всегда можете отключить рекламу.

Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Федотов Илья Евгеньевич

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «О направлениях развития дисциплины параллельного программирования»

О направлениях развития дисциплины параллельного программирования

И.Е. Федотов, Московский государственный технический университет радиотехники, электроники и автоматики (МГТУМИРЭА), доцент, fedotov. i.e@inbox. т

Рассмотрена проблема текущего состояния дисциплины параллельного программирования в сфере образования. Приведены аргументы в пользу включения в образовательный процесс описания высокоуровневых моделей параллельного программирования с возможностью их реализации. Приведено несколько примеров высокоуровневых моделей, позволяющих организацию параллельных программ и предлагаемых для рассмотрения в процессе преподавания параллельного и распределенного программирования.

Введение

Вот уже несколько лет, как современные компьютеры вплотную приблизились к своему пределу тактовых частот. Производительность процессоров (точнее, их отдельных ядер) перестала нарастать сказочными темпами, и теперь остается возможность обеспечить дальнейшее повышение вычислительных мощностей лишь за счет увеличения их количества: производительность компьютеров начала расти «вширь», а не «в высоту». В связи с этим параллельное программирование уже перестало быть узкоспециализированной дисциплиной для высокопроизводительных вычислений и приобретает все большую актуальность для широких программистских масс.

Есть немало образовательной литературы, посвященной рассмотрению архитектур параллельных вычислительных систем и теоретическим вопросам распараллеливания последовательных алгоритмов. Также существует достаточно учебных пособий и статей, посвященных рассмотрению существующих технологий, программных интерфейсов и библиотек. Однако оба эти направления охватывают довольно низкоуровневые аспекты параллельного программирования. Высокоуровневая же организация параллельных вычислений в принципе не должна быть привязана к конкретной реализации параллелизма, она лишь должна предоставлять пользователю набор абстракций для такой организации программы, при которой нижележащая система, исполняющая эту программу, сможет

самостоятельно автоматически выполнить распараллеливание ее работы.

Существует достаточно много моделей, позволяющих на высоком уровне описывать выполнение параллельных процессов и их взаимодействие. Такие модели уже являются основой многих программных технологий и некоторых не слишком популярных инструментов построения параллельных программ. Таким моделям посвящено немало учебного материала теоретического характера. В то же время, они незаслуженно обходятся стороной в образовательном процессе в контексте непосредственного применения их при организации работы параллельных программ. Поскольку реальную актуальность параллельное программирование приобрело сравнительно недавно, представляется вполне естественным тот факт, что эта ниша в дисциплине все еще пустует. С другой стороны, если эта ниша не будет заполнена в образовательном процессе, она так и не будет полноценно реализована в промышленности.

Можно привести довольно иллюстративную аналогию. Известно немало алгоритмов работы с данными, таких как сортировка и поиск, а также структур данных, таких как B-деревья и хеш-таблицы, предназначенных для обеспечения быстрого доступа к хранимым данным. Также аппаратурой, операционными системами и библиотеками предоставляется немало интерфейсов для доступа к локальным или удаленным данным. Всей этой информации, в принципе, достаточно для реализации эффективной работы с большими объемами данных. Тем не менее, это не лишает полезности, к примеру, изучения реляционной модели данных и правил приведения отношений к нормальным формам. Более того, абсолютное большинство в повседневной практике использует именно эту высокоуровневую модель, а знание алгоритмов, с помощью которых реализуется работа с данными на низком уровне, нужны лишь тем немногим, кто занимается разработкой СУБД. Можно сколько угодно говорить о том, что возможности мозга безграничны, но следует учитывать и человеческий фактор: именно с целью упрощения человеко-ориентированного описания задачи были придуманы, к примеру, структурное и объектно-ориентированное программирование.

Проблема параллельного программирования

Главная проблема параллельного программирования основана на относительной сложности построения схемы параллельных вычислений в голове программиста. Человек в принципе мыслит последовательно. Здесь, разумеется, имеется в виду процесс построения умозаключений, а не внутренние процессы мозга на физиологическом уровне. Именно поэтому последовательны большинство существующих сегодня языков

программирования. Многие авторы, работающие в области параллельного программирования, сходятся во мнении, что развитой дисциплины параллельного программирования на сегодняшний момент нет, и что индустрия создания параллельных программ движется по тупиковому пути [4, 5, 9].

Также многие считают, что для описания параллельных программ необходимо уйти от императивных языков программирования [1, 2]. Императивные языки описывают, какие действия и в каком порядке следует выполнить, чтобы получить результат. В данном же случае требуется использование декларативных языков, т.е. таких, которые описывают, чем является результат, который должен быть получен, оставив выполнение действий, как и выбор их последовательности, на долю компилятора или интерпретатора. Различие между императивным и декларативным программированием в чем-то напоминает различие между прямым вычислением функции и решением уравнения, т.е. обращением функции.

С момента становления программирования как дисциплины декларативным языкам пророчили большое будущее, поскольку они зачастую позволяют легко, наглядно и потому надежно описать задачу, что само по себе обычно гораздо проще, чем детально описывать процесс ее решения. При этом возникает другая сложность: создание эффективного компилятора или интерпретатора, который, в общем-то, и принимает в этом случае бремя принятия решений о выполнении действий, снятое с плеч программиста.

Несмотря на потенциальную мощь, декларативные языки не приобрели широкой популярности. Одна из возможных причин заключается в том, что на момент их появления мощности машин не хватало для реализации достаточно эффективных компиляторов и интерпретаторов. Вследствие этого программисты были вынуждены пользоваться языками, которые позволяют «подсказать», а вернее даже «повелеть» машине выполнение конкретных действий, т.е. императивными языками.

Ситуация здесь сродни той, почему в прежние времена было популярно использование низкоуровневых языков. Оптимизирующие компиляторы языков высокого уровня и вычислительные системы, на которых они работали, не были достаточно мощными, чтобы обеспечить производительность и размер программ, сравнимые с программами на языках низкого уровня. Когда оптимизаторы кода достигли приемлемой производительности, программирование на языках низкого уровня постепенно утратило популярность в угоду повышению переносимости.

Развитие вычислительных мощностей сказалось также и на повышении эффективности использования компиляторов и интерпретаторов декларативных языков. Более того, в отношении смены парадигмы на декларативную теперь также появился стимул: перенос реализации механизмов распараллеливания с программистов на компиляторы и интерпретаторы. Такие механизмы являются частью системы, и забота о них не должна лежать на плечах прикладного программиста. Поэтому можно надеяться, что в скором времени изменится и отношение к декларативному программированию.

Многие могут возразить: зачем использовать декларативные языки, если машина все равно выполняет императивный поток инструкций? С тем же успехом можно спросить, зачем вообще использовать языки высокого уровня, если можно программировать сразу в машинных инструкциях. Машина «мыслит» совершенно не так, как человек, и здесь не возникает разногласий. Человеку нелегко дается описывать задачу в терминах машины. Высокоуровневое же программирование призвано быть как раз промежуточным слоем, обеспечивающим преобразование описания задачи, представленного в терминах человека (на формальном, но все же приближенном к представлению человека языке), в описание той же задачи, представленное в терминах машины. Чем проще, естественнее и точнее высокоуровневый язык позволяет человеку описать свою задачу, тем лучше он соответствует своему назначению. В этом отношении декларативные языки, определенно, во многих областях опережают императивные.

Многие существующие уже давно языки декларативного программирования, несмотря на свою мощь, не обеспечивают полноценной базовой платформы для удобного описания программы с возможностью неявной передачи присущей ей внутренней параллельной структуры. Причина, вероятно, в том, что спецификации этих языков создавались тогда, когда вопрос параллельного программирования не стоял так остро, как сегодня, и, видимо, поэтому в них зачастую содержатся ограничения, также сводящие вычисления к последовательным. К примеру, наличие в языке Lisp операции присваивания вносит необходимость задания четкого порядка для вычисления последовательности выражений (к примеру, аргументов функции), что лишает интерпретатор права распараллелить этот процесс, даже если программисту этот порядок не важен [1].

Выходит, для полноценного удобного описания параллельных программ, так или иначе, требуется более современный язык. Возможно, им станет один из уже существующих языков, попыток создания которых, в том числе весьма удачных, на сегодняшний момент известно немало. Эти языки, несмотря не свои достоинства, пока не

обрели достаточно широкой популярности, и можно лишь надеяться, что они обретут ее в будущем. В противном случае можно надеяться, что появятся и обретут широкую популярность другие высокоуровневые языки для описания параллельных программ.

Следует понимать, что под прозвучавшим утверждением об отсутствии популярных языков параллельного программирования подразумевалось отсутствие таких языков, которые не ориентированы на какую-либо узкоспециализированную область применения и которые используются для реализации параллельных вычислений повсеместно. Стоит отметить, что популярность средства программирования очень важна в сегодняшних условиях, когда большинство программистов вынуждены быть «совместимыми» друг с другом. Временные затраты на освоение многочисленных, хоть и прогрессивных, но зачастую мало распространенных технологий, как правило, не оправдывают себя, вследствие чего большинство программистов вынуждены консервативно пользоваться решениями с использованием, порой, не самых удачных, но устоявшихся средств.

Возможные направления

Мы не будем говорить о каких-либо конкретных языках программирования, специально ориентированных на выполнение параллельных вычислений, поскольку выбор как такового языка непринципиален. Напротив, не исключено, что в образовательном процессе стоит иллюстрировать существующие высокоуровневые подходы и методы параллельного программирования на основе популярных императивных языков, чтобы не создавать ложного впечатления привязки к конкретным языкам.

Мы приведем несколько существующих сегодня моделей, используемых для параллельного программирования и, порой, выдвигаемых их приверженцами в качестве универсальной основы для построения параллельных программ. Рассматриваемые модели являются по существу разными, и в то же время во многом напоминают друг друга, что дает возможность неформально говорить о некоторых обобщениях и усовершенствованиях одной модели для формирования другой.

Возможные подходы к построению параллельных программ не ограничиваются рассмотренными моделями. Разумеется, ни одна из них не является панацеей и не дает возможности простого описания для любой задачи. Одни задачи наиболее удобно описываются одной моделью вычислений, другие - другой, а третьи наиболее просто и наглядно описываются простым циклом на императивном языке. Тем не менее, понимание таких моделей и парадигм в комплексе может существенно упростить разработку параллельных программ с той точки

зрения, что даст возможность программисту смотреть шире и сгладит отсутствие у него «параллельного мышления».

Ярусно-параллельная форма программы

Самым, пожалуй, простым представлением параллельного алгоритма является ярусно-параллельная форма программы, базовое представление в виде направленного ациклического графа, в котором выявляются наборы информационно независимых друг от друга операций. Модель предполагает, что все рассматриваемые операции выполняются единожды, поэтому граф не может содержать циклических зависимостей, поскольку ни одна операция не должна зависеть сама от себя. Также вследствие однократного выполнения операций отсутствует необходимость хранения ими промежуточного состояния. В сущности, такая схема логически параллельного выполнения реализуется в чистом функциональном программировании (без возможности присваивания и, как следствие, без побочных эффектов и необходимости введения четкого порядка выполнения последовательности операторов). Похожий подход используется и при решении задач, описанных в терминах модели потоков данных (dataflow), а также в языках программирования, использующих понятие будущих значений (futures).

Сети конечных автоматов

Следующая рассматриваемая модель - сети конечных автоматов. Все автоматы в автоматной сети работают параллельно и синхронно по тактам, при этом предполагается, что тактов в общем случае много. Как следствие, в таких сетях появляется возможность циклических зависимостей автоматов, поскольку выходные данные автомата могут прямо или косвенно вернуться на вход ему же. В этих условиях оказывается довольно уместным наличие у автомата внутреннего состояния, т.к. это существенно повышает удобство моделирования ими объектов реального мира. Таким образом, сети конечных автоматов в некотором роде обобщают предыдущую модель, являясь, по сути, расширением ярусно-параллельной формы высотой в один ярус наличием обратных связей и хранением промежуточного состояния элементов.

Все параллельно работающие автоматы синхронизируются между тактами, таким образом, состояние всей сети между тактами четко определяется совокупностью состояний внутренних автоматов сети (а также значений сигналов, передаваемых между автоматами) [6]. Программа, построенная на основе этой модели, должна обеспечивать эту синхронизацию, что имеет свои положительные и отрицательные стороны. С одной стороны, вычисления происходят в полностью

детерминированном порядке, независимо от производительности узлов, на которых физически размещаются соответствующие программные автоматы, и в любой момент вычисления можно сказать, в каком состоянии находится система. С другой стороны, крайне затруднительно обеспечить эффективную синхронизацию автоматов между сильно удаленными узлами распределенной системы, что сужает область эффективного применения модели до систем с общей памятью. К тому же, сама по себе схема потактового взаимодействия автоматов обуславливает некоторые усложнения в человеко-ориентированном представлении решения стоящей задачи. К примеру, возможна ситуация, когда некоторый автомат работает со сменой состояний так, что ожидает приема данных не на каждом такте, а через один. В это же время другой автомат, который должен передать данные первому, работает независимо и потому не следит за его состоянием. В этом случае за тем, чтобы данные пришли именно в приемный такт, должен следить программист, что добавляет ему головной боли. Обе упомянутые проблемы решаются в модели актеров.

Сети Петри

Сеть Петри, в свою очередь, можно считать некоторым обобщением конечного автомата, который может находиться одновременно в нескольких состояниях и в общем случае перестает быть конечным. В некотором приближении можно сказать, что сеть Петри добавляет конечному автомату некоторые свойства, присущие сетям конечных автоматов.

Сети Петри представляют собой аппарат моделирования динамических дискретных систем и являются одним из наиболее удобных способов описания асинхронного выполнения параллельных процессов, в том числе в распределенных системах. Широко распространено мнение, что они являются исключительно инструментом моделирования, а не построения программ. Тем не менее, задачей большинства программ по сути как раз и является моделирование каких-либо процессов. К примеру, компьютерные игры, как правило, являются сильно упрощенными моделями реальной жизни. Программы управления оборудованием обычно описывают некую виртуальную модель реального оборудования, в которую поступает информация с реальных датчиков и от которой исходят управляющие сигналы. Поэтому сети Петри могут являться мощным средством не только моделирования, но и организации программ, в том числе параллельных.

Разметка сети описывает глобальное состояние системы. Для выполнения срабатывания очередного перехода в общем случае нужен анализ текущей разметки всей сети, что обуславливает узкое место в

реализации ее работы. Это снова ограничивает возможность использования сетей Петри для организации распределенных программ. С другой стороны, проблема в большой степени может быть решена путем использования строго иерархических сетей [3], в которых вложенная сеть, не имеющая связей внутренних элементов с внешними по отношению к ней, может выполняться автономно до полного завершения работы. В таком случае существенно сокращается объем передаваемой информации о разметке сети, поскольку сети верхнего уровня нужно лишь знать, жива ли еще вложенная сеть или уже нет, тогда как детали ее внутренней разметки для выбора следующего срабатывания во внешней сети не нужны.

Модель актеров

Модель актеров обобщает уже сети конечных автоматов, снимая некоторые их ограничения, такие как необходимость глобальной синхронизации и четкий порядок поступления данных, и тем самым добавляя новые возможности. Одним из главных достоинств и в тоже время недостатков сетей конечных автоматов является наличие глобальной синхронизации всех автоматов сети между выполнением отдельных тактов. С одной стороны, наличие синхронизации делает вычисления полностью детерминированными, что сильно облегчает реализацию многих алгоритмов. С другой стороны, глобальную синхронизацию оказывается довольно сложно реализовать эффективно в распределенных системах.

Модель актеров лишена такого недостатка, поскольку исключает синхронизацию отдельных вычислительных элементов (актеров) между собой. Каждый актер обладает состоянием (поведением) и может выдавать выходные данные (сообщения) в ответ на входные, но, в отличие от автомата, делает это не одновременно со всеми, а лишь по приходу входного сообщения. Отправка сообщения асинхронна, время его доставки не определено, также как и порядок доставки. В связи с этим в модели теряется вообще понятие глобального состояния, поскольку само по себе глобальное состояние никому неинтересно -важна лишь ситуация с точки зрения наблюдателя, т.е. какого-либо из актеров, а она относительна. Отсутствие глобального состояния снимает проблему необходимости неявной синхронизации, изначально ориентируя программиста на создание системы, не привязанной к ее наличию.

Поскольку порядок доставки не определен, а актер может ожидать сообщения разных типов, для ожидания в некоторый момент сообщения определенного типа используется сопоставление с образцом (pattern matching) [7, 8]. Это решает проблему с приходом сообщений в тот момент, когда ожидаются сообщения другого типа.

Еще одно преимущество модели актеров заключается в возможности динамического роста системы в рамках распределенной среды, поскольку, в отличие от сетей конечных автоматов, в ней существует операция создания новых актеров. Подобная гибкость и удобство для выполнения распределенных вычислений обусловили сегодняшнюю популярность модели актеров. Во многих языках модели, близкие к модели актеров, реализованы на уровне языковых средств или на уровне библиотек.

Заключение

В настоящей статье ставилась задача показать проблему современного параллельного программирования, заключающуюся, прежде всего, в том, что наиболее популярные средства программирования приспособлены к описанию методов решения стоящей задачи в соответствии с образом мышления программиста, а именно в последовательной форме. Отсюда вытекает сложность наглядного для человека представления с использованием таких средств параллельных алгоритмов и программ. В связи с этим встает ребром вопрос необходимости использования для параллельного программирования принципиально иных средств, не являющихся модификациями или надстройками существующих популярных языков. Одним из возможных направлений является декларативное программирование. В рамках всех описанных моделей рассматриваемые задачи представляются декларативно: графом зависимостей, диаграммой состояний автомата, схемой автоматной сети, схемой сети Петри, схемой взаимодействия актеров и набором описаний их поведения.

С другой стороны, императивные языки могут без серьезных препятствий быть использованы для прозрачной (неявной) реализации параллельных алгоритмов. При этом может быть реализована некая абстрактная машина, принимающая на входе набор декларативно описывающих алгоритм данных, которая инкапсулирует внутри себя механизмы параллельного выполнения. Программный интерфейс такой машины принципиально не зависит от средств распараллеливания, с помощью которых она реализована и которые в общем случае могут быть разными. Параллельное выполнение декларативно описанной программы зависит от внутренней реализации соответствующей машины, а не возлагается на плечи программиста. Реализация соответствующего механизма может быть как последовательной, так и параллельной с использованием различных подходов к организации физического параллелизма. Такой подход позволит не уходить от имеющейся на сегодняшний момент ситуации преобладания

императивных языков и, тем самым, в какой-то степени упростит и

сгладит освоение параллельного программирования.

Литература

1. Глебов А.Н. Параллельное программирование в функциональном стиле. -2003 [Электронный ресурс] URL: http://www.softcraft.ru/parallel/ppfs.shtml.

2. Дехтяренко И.А. Декларативное программирование. - 2003 [Электронный ресурс] URL: http://www.softcraft.ru/paradigm/dp/.

3. Котов В.Е. Сети Петри. - М.: Наука, 1984. - 160 с.

4. Кузнецов С.Д. Блеск и нищета легковесных процессов // Computerworld Россия. - 1996. №31.

5. Любченко В.С. К проблеме создания модели параллельных вычислений // Труды Третьей международной конференции «Параллельные вычисления и задачи управления» (РАС0'2006). Москва, 2-4 октября 2006 г. Институт проблем управления им. В.А. Трапезникова РАН. - М.: Институт проблем управления им. В.А. Трапезникова РАН, 2006. - С. 1359-1374.

6. Федотов И.Е. Приемы параллельного программирования: Учебное пособие. - М.: РосНОУ, 2009. - 184 с.

7. Agha G.A. Actors: A Model of Concurrent Computation in Distributed Systems. -Cambridge, Massachusetts: MIT Press, 1986. - 190p.

8. Hewitt C., Bishop P., Steiger R. A Universal Modular Actor Formalism for Artificial Intelligence // International Joint Conference on Artificial Intelligence. -Stanford, California. 1973. - P.235-245.

9. Lee Edward A. The problem with threads // IEEE Computer. - Vol.39, №5, May 2006. - P. 33-42.

i Надоели баннеры? Вы всегда можете отключить рекламу.