На правах рукописи - Parallel C# Homepage

advertisement
На правах рукописи
Гузев Вадим Борисович
РАСШИРЕНИЕ ЯЗЫКОВ
ПАРАЛЛЕЛЬНОГО ПРОГРАММИРОВАНИЯ
ДЛЯ МНОГОПРОЦЕССОРНЫХ И
РАСПРЕДЕЛЕННЫХ СИСТЕМ
Специальность 05.13.11 –
“Математическое обеспечение вычислительных машин, комплексов и
компьютерных сетей”
АВТОРЕФЕРАТ
диссертации на соискание ученой степени
кандидата технических наук
Москва - 2009
Работа выполнена на кафедре информационных технологий Российского
Университета Дружбы Народов.
Научный руководитель:
кандидат физико-математических наук,
профессор
Толмачев Игорь Леонидович
Официальные оппоненты:
доктор физико-математических наук,
г.н.с. Института программных систем РАН
Новосельцев Виталий Борисович,
Ученая степень,
ученое звание,
фамилия, и., о
Ведущая организация:
Московский Государственный Университет
Защита состоится “__” ___________ 2009 г. в __ час. __ мин. на заседании
диссертационного совета ___(шифр совета, название организации, адрес)___
С диссертацией можно ознакомиться в библиотеке
______(название организации, в которой создан совет)__________________
Автореферат разослан “__”______ 2009 года.
Ученый секретарь
диссертационного совета,
2
ОБЩАЯ ХАРАКТЕРИСТИКА РАБОТЫ
Актуальность темы. Для решения больших вычислительных задач
создаются мощные многоядерные компьютеры, позволяющие выполнять
огромное количество операций в секунду. Наряду с этим разработчики
вычислительной техники значительное внимание уделяют расширяемым
системам, в которых производительность определяется количеством
вычислительных узлов (процессоров, компьютеров, кластеров или сайтов – в
терминологии принятой при описании распределенных систем), объединяемых
посредством высокоскоростной сети передачи данных. Этот подход требует
создания высокоуровневых, сложных и в то же время надёжных систем
исполнения (Runtime system), эффективно использующих возможности
параллельных распределённых вычислений и легко расширяемых на произвольно
заданное количество узлов. Работа направлена на совершенствование моделей
существующих объектно-ориентированных языков программирования, решается
задача их «гладкого» расширения для поддержки распределенного параллельного
программирования.
Исследования в данной области непрерывно ведутся, начиная с 1980-х гг.
Было разработано множество расширений существующих языков: T++, Cilk,
Unified Parallel C, Charm++, ZPL, HiPE, MultiLISP, Concurrent Haskell, Join Java,
JoCaml и др.
В 1995 г. Cedric Fournet и Georges Gontier из института INRIA разрабатывают
join-исчисление – процессную алгебру, представляющую формальный базис для
разработки распределенных языков программирования. Данное расширение имело
одно преимущество по сравнению с π-исчислением – возможность определения
специальных паттернов-связок, которые позволяют
выполнять некоторые
действия при нахождении соответствий в поступающих по разным каналам
сообщениям.
Появление join-исчисления привело к созданию целого семейства join-языков.
В 2002 г. в Университете Южной Австралии создается язык Join Java, являющийся
расширением языка Java. В 2003 г. корпорация Майкрософт спонсирует
исследования по созданию языка Polyphonic C#, который позже был объединен с
языком Cω (COmega) и теперь является кандидатом на слияние в следующих
релизах с языком C#.
Исследования в направлении расширения существующих языков также ведут
такие компании как IBM (язык X10, расширяющий язык Java), Intel (Cluster
OpenMP, расширяющий языки C++ и Fortran), Sun Microsystems (язык Fortress,
расширяющий язык Fortran) и др.
3
К сожалению, среди отечественных разработок на сегодняшний день можно
выделить лишь три языка, разработанных в рамках Института программных
систем РАН: T++ (расширение языка C++, созданный в рамках
суперкомпьютерной программы SKIF России и Белоруссии), T# и MC#
(расширения языка C#).
Цель исследований. Цель диссертационной работы – разработка и
экспериментальная реализация модели языковых конструкций расширяющей
синтаксис существующих объектно-ориентированных языков программирования
в части поддержки параллельного программирования.
Основные задачи
1.Выделение общих синтаксических и семантических элементов в
параллельных языках программирования.
2.Разработка синтактико-семантической модели (специального исчисления),
расширяющей семейство объектно-ориентированных языков программирования.
3.Программная реализация модели на примере языка Parallel C#,
расширяющего язык C#.
4. Проведение экспериментальных исследований на кластерных установках.
Методы исследования
Реализация языковой модели базируется на методах параллельного
программирования, теории алгоритмов и Join-исчислении (формальном базисе,
используемом для разработки распределенных языков программирования).
Основные положения, выносимые на защиту.
1. Модель
«гладкого»
расширения
существующих
языков
программирования, интегрирующая функциональные типы/функции
высшего порядка и связки методов.
2. Грамматика языка программирования Parallel C# (являющегося гладким
расширением существующего языка C#), реализующего предлагаемую
модель параллельного программирования.
3. Реализация системы исполнения и компилятора для языка Parallel C#:
 для кластерных архитектур на базе Linux-платформ;
 для многоядерных/многопроцессорных компьютеров на базе
Windows-платформ.
4. Результаты
экспериментальных
исследований
по
замерам
производительности (на различных количествах процессоров) тестовых
программ, написанных на языке Parallel C#.
4
Научная новизна результатов исследования.
1. Впервые скомпонованы в одной языковой модели функциональные
типы/функции высшего порядка и связки асинхронных и синхронных методов,
служащих средством синхронизации потоков, что обеспечило упрощение
языковой модели (отпала необходимость в добавлении каналов и обработчиков
канальных сообщений по сравнению с моделью языка MC#).
2. Разработаны правила трансляции новых синтаксических конструкций в
языки низшего уровня и представлена практическая реализация данных правил на
примере языка Parallel C#, которая обеспечивает повышение качества и скорости
написания параллельных программ за счет автоматизированной трансляции
компактного кода параллельных программ в языки более низкого уровня.
Практическая значимость работы. Разработанная модель расширения
существующих объектно-ориентированных языков программирования позволяет
повысить эффективность работы программистов при написании параллельных
программ за счет компактного синтаксиса и автоматической генерации кода в
языках более низкого уровня (отношение объема сгенерированного кода к объему,
написанному программистом в среднем равно 10 к 1).
Новизна технического решения и полученных результатов была
подтверждена присуждением в 2006г. автору работы награды “Best Student Paper”
от организаторов (DARPA High Productivity Computing Systems Program и IDC)
международного конкурса языков программирования HPC Challenge Award
Competition (www.hpcchallenge.org).
Реализация результатов работы. Результаты работы внедрены на ЗАО
«СиБОСС» в виде программного комплекса и проектной документации (акт
испытаний программного обеспечения от DD.MM.YYYY г. № XX/YY).
Апробация работы.
Основные результаты работы представлялись на следующих конференциях и
семинарах:
 “The 2008 International Conference on Parallel and Distributed Processing
Techniques and Applications (PDPTA'08)”, Monte Carlo Resort, Las Vegas, Nevada,
USA (July 14-17, 2008);
 “XLIV
Всероссийской
Конференции
по
Проблемам
Математики,
Информатики, Физики и Химии, секция “Программные Системы”, г. Москва,
Российский Университет Дружбы Народов (21-25 апреля 2008 г.);
 “Всероссийская научная конференция "Научный сервис в сети Интернет:
технологии распределенных вычислений”, г. Новороссийск (19-24 сентября
2005 г.);
5
 “II-й Белорусский космический конгресс”, Минск (25-27 октября 2005 г.);
 “XII-ой международная конференция по вычислительной механике
и
современным прикладным программным системам (ВМСППС'2003)”, г.
Владимир (30 июня - 5 июля 2003 г.);
 “Международная конференция Parallel Computing Technologies 2003
(PACT'2003)”, Нижний Новгород (15-19 сентября 2003);
 “Технологии Microsoft в научных исследованиях и высшем образовании”,
Научно-техническая конференция по программированию, Москва (15-17 июня,
2003 г.);
 “1st International Workshop on C# and .NET Technologies on Algorithms,
Computer Grafics, Visualilization, Distributed and WEB Computing (C# and .NET
Technologies'2003)”, University of West Bohemia, Plzen, Czech Republic (5-7
February, 2003);
 сообщения и доклады на научно-практических и научно-методических
конференциях РУДН в 2007-2008 гг.
Основное содержание диссертации отражено в 7 научных работах, включая
одну публикацию в издании из списка ВАК.
Объем и структура работы. Диссертационная работа состоит из введения, 3
глав, заключения, библиографического списка, включающего 54 наименований и
практической реализации предлагаемой модели, представленной на сайте
http://www.parallelcsharp.com. Работа изложена на 119 листах машинописного
текста, содержит 8 рисунков.
ОСНОВНОЕ СОДЕРЖАНИЕ ДИССЕРТАЦИИ
ВО ВВЕДЕНИИ обоснована актуальность работы и формулируются
основные задачи диссертации.
В ПЕРВОЙ ГЛАВЕ выполнен аналитический обзор, посвященный
выделению общих синтаксических и семантических элементов в параллельных
языках программирования T++, CILK, Polyphonic C#, X10 и MC#. Отмечается
тенденция увеличения уровня абстракции и гранул параллелизма в создаваемых
языках программирования. Установлено, что создателей новых параллельных
языков программирования интересует не столько распараллеливание отдельных
арифметических операций, сколько распараллеливание на уровне функций и
объектов.
6
ВТОРАЯ ГЛАВА посвящена описанию новой языковой модели, практически
реализованной в рамках данной работы на примере языка Parallel C#.
Определение 1: Языковая модель (calculus, исчисление) – совокупность
формального описания грамматики и операционной семантики некоторого
родственного семейства языков.
Каждая языковая модель характеризуется определенным набором синтактикосемантических элементов. Например, все языки модели «Функциональный язык
программирования» содержат элементы «функция», «вызов функции», «область
видимости». А все языки модели «Объектно-ориентированный язык
программирования» содержат элементы «объект», «класс», «метод».
Основная идея, предлагаемая в рамках данной работы, состоит в том, что с
помощью добавления пяти новых элементов можно расширить языковую модель
«Объектно-ориентированный
язык
программирования»
до
модели
«Распределенный параллельный язык программирования» (т.е. фактически можно
расширить существующие объектно-ориентированные языки программирования
до языков параллельного программирования). Ниже приведен список этих
элементов:
1. Порождение нового потока на локальном узле с помощью асинхронных
методов (заимствовано из Java, Nemerle, Polyphonic C#);
2. Синхронизация асинхронных и синхронных методов с помощью связок
(заимствовано из языка Polyphonic C#);
3. Использование функциональных типов/функций высшего порядка
(заимствовано из функциональных языков программирования);
4. Порождение нового потока на удалённом узле с помощью перемещаемых
методов (заимствовано из языка Т++);
5. Автоматическая генерация прокси-функций (аналог Т-указателей на
функции существует в Т++).
Назовем для краткости полученную модель «||-исчислением» (читается как
«параллельное исчисление»), формализованное описание которой будет
приведено далее.
На рис. 1
ориентированных
элементов:
приведена общая схема совершенствования объектноязыков программирования с помощью вышеуказанных
7
Объектноориентированный язык
программирования
Асинхронный
параллельный язык
программирования
+
+
Асинхронные методы
Перемещаемые методы
+
+
Связки
Автоматическая генерация
прокси-функций
+
+
Функциональные типы /
функции высшего порядка
Распределенная система
исполнения
Распределенный
параллельный язык
программирования
+
Локальная система
исполнения
Рис. 1. Схема совершенствования объектно-ориентированных языков программирования
Экспериментально доказано (на примере реализации языка Parallel C#), что
добавления этих конструкций достаточно для удобного написания параллельных
распределённых программ любой сложности. Стоит ещё раз подчеркнуть, что с
помощью данных конструкций можно легко расширить многие другие языки
программирования, такие как Java и Nemerle, т.е. модель рассчитана не только на
один конкретный язык программирования.
В разделах 2.1-2.3 описаны синхронные, асинхронные и перемещаемые типы
методов для параллельных вычислительных систем.
Определение 2: Синхронный метод – метод, при вызове которого сторона,
инициировавшая вызов метода, приостанавливает свою работу до завершения
выполнения вызванного метода на том же узле вычислительной системы, где был
произведен вызов.
Определение 3: Асинхронный метод – метод, при вызове которого сторона,
инициировавшая вызов метода, не приостанавливает свою работу после вызова
метода, а продолжает выполняться параллельно с вызванным методом на одном
узле вычислительной системы.
Определение 4: Перемещаемый метод – подтип асинхронного метода,
выполнение которого может производиться на любом из узлов вычислительной
системы.
На рис. 2 приведены примеры объявлений и использования вышеуказанных
типов методов, а также приведены диаграммы поведений, из которых видны
особенности их исполнения.
8
Синхронный метод
Асинхронный метод
Перемещаемый метод
void fun() {
// Бизнес-логика 1
}
…
void main() {
// Бизнес-логика 2
fun();
// Бизнес-логика 3
}
async fun() {
// Бизнес-логика 1
}
…
void main() {
// Бизнес-логика 2
fun();
// Бизнес-логика 3
}
movable fun() {
// Бизнес-логика 1
}
…
void main() {
// Бизнес-логика 2
fun();
// Бизнес-логика 3
}
Компьютер 1
Компьютер 1
Поток 1
Поток 1
Компьютер 1
Компьютер 2
Поток 1
Поток 2
fun
fun
Поток 2
fun
Рис. 2 Демонстрация различий между синхронными, асинхронными и перемещаемыми
методами
Предполагается, что перемещаемые методы могут выполняться на любом
узле кластера, метакластера или GRID-сети (в зависимости от фактически
используемой вычислительной системы). При этом система исполнения языка
выбирает для выполнения перемещаемого метода наименее загруженный узел
вычислительной системы. Стоит также отметить, что асинхронные и
перемещаемые методы не могут возвращать напрямую никаких значений.
В разделе 2.4 вводятся объекты функционального типа, которые можно
использовать при объявлении полей и свойств класса, использовать в качестве
локальных переменных, а также передавать в качестве параметров другим
функциям, в том числе перемещаемым. Пример объявления и использования
функциональных типов:
class A {
// Объявление поля-объекта типа "функция",
// принимающую в качестве параметра целое число int
// и возвращающую значение типа long
9
public (int) => long fun1;
}
class B {
public long func( int x ) { return x * x; }
public fun2() {
A a = new A();
// Инициализация поля-объекта типа "функция"
a.fun1 = this.func;
Console.WriteLine( a.fun1( 2 ) ); // Выводит "4"
// Локальный указатель на функцию
() => long function = this.func;
Console.WriteLine( function( 2 ) ); // Выводит "4"
}
}
Описанная в работе языковая модель предполагает, что базовым языком
программирования может являться сложный объектно-ориентированный язык.
Для передачи объектов с одного узла вычислительной системы на другой
используются механизмы автоматической сериализации/десериализации, которые
описаны в разделе 2.5.
В случае передачи функций в качестве параметров другим функциям
генерируются специальные прокси-функции (указатели на функции, которые
должны быть запущены на узлах, где они были изначально созданы). В
зависимости от типа базовой функции, для которой создаются прокси
(асинхронная или синхронная), сама прокси-функция может быть асинхронной
или синхронной.
Очень часто в параллельных программах необходимо дожидаться результатов
работы нескольких параллельно выполняемых функций (возможно работающих
на разных узлах системы). В разделе 2.9 для этих целей вводится понятие "связок
методов" (bounds, joins), которое было заимствовано из языка Polyphonic C#.
Определение: Связка – средство синхронизации нескольких параллельно
исполняемых потоков, в котором:
 в заголовке связки могут быть объявлены один или несколько
асинхронных методов и не более одного синхронного метода;
 может быть объявлено только одно тело связки (набор команд), которое
срабатывает тогда и только тогда, когда все методы, объявленные в
заголовке связки были вызваны;
 тело связки возвращает результат того же типа, что и объявленный в
заголовке связки синхронный метод (если он присутствует).
10
Пример объявления связки:
int Get() & async Result(int x) {
return x;
}
В данном примере в связке находится один асинхронный метод Result и один
синхронный метод Get. Тело связки состоит из одного оператора – возврата
целочисленного значения, поступившего при вызове метода Result.
При вызове метода Get производится проверка: не был ли уже вызван метод
Result. Если этот метод вызван не был, то текущий поток (вызвавший метод
Get) блокируется до тех пор, пока метод Result не будет вызван. Когда будет
произведен этот вызов, сработает тело связки (а вместе с тем произойдёт чтение и
извлечение параметров из специальной очереди, относящейся к методу Get).
Если же на момент вызова метода Get метод Result уже был вызван, то
тело связки срабатывает моментально (и производится чтение и извлечение
параметров из очереди метода Result).
Наоборот: если при вызове метода Result метод Get ещё не был вызван, то
параметры вызова ставятся в очередь для "последующего использования". Как
только метод Get будет вызван, то параметры будут браться из этой очереди.
Если же на момент вызова метода Result метод Get уже был вызван, то
происходит срабатывание связки (и соответственно происходит чтение и
извлечение параметров из очереди метода Get).
Методы могут участвовать в нескольких связках одновременно – в этом
случае может появиться недетерминизм и языковая модель не декларирует особых
правил по выбору конкретной связки, которая должна сработать первой в случае
одновременного срабатывания всех методов. Например, в следующем примере
метод wait участвует сразу в двух связках:
int wait() & async sum(int x) { return x; }
int wait() & async part1(int x) &
async part2(int y) { return x + y; }
Основное отличие ||-исчисления от join-исчисления состоит в том, что в
качестве базовой операции используется не отправка сообщения, а вызов метода.
В зависимости от месторасположения сайта-получателя и типа вызываемого
метода сообщение отправляется на удаленный или локальный узел. Кроме того,
ссылки на функции можно передавать в качестве параметров другим функциям,
т.е. они являются полноценными объектами, в отличие от языка C#.
11
В ||-исчислении используются следующие обозначения: o - имена объектов;
sm - синхронные методы; am - асинхронные методы; mm -перемещаемые методы;
s, r, …- названия сайтов. Имена могут быть простыми или составными: во втором
случае объекты от методов разделяются точкой, например, o.am. Кроме того,
имена могут иметь нижние индексы, например, s1, o2 и т.д. Конечный список
~
выражений обозначается E . В таблице 1 приведены базовые конструкции
синтаксиса ||-исчисления:
Табл. 1.
Синтаксическая
Выражение
категория
AJ::=
 
~
am E
| AJ1 & AJ2
SM::= sm E 
~
Комментарий
Асинхронная связка
асинхронный метод
связка асинхронных методов
Синхронный метод
SJ::= SM & AJ
Синхронная связка
D::=
Объявление методов объектов
именованный процесс
правило реакции для асинхронной связки
правило реакции для синхронной связки
дизъюнкция определений
 
~
d E :P
| AJ ‣P
| SJ ‣ return E
| D1, D2
O::=
x=D
| O1; O2
Объявление объектов
объявление одного объекта
объявление нескольких объектов
(композитное объявление)
| sm E 
Выражения
имя
числовые/строчные/буквенные значения (не
описываем здесь)
вызов синхронного метода
0
Процессы
пустой процесс
E::=
u
|…
~
P ::=
12
| x.smE 
~
| x.amE   ls
~
| x.mmE   s
| P1 || P2
| obj O in P
~
вызов синхронного метода
вызов асинхронного метода на локальном
сайте ls
вызов перемещаемого метода на сайте s
параллельное исполнение
локальное определение объекта в процессе P
Как и в join-исчислении базовая часть ||-исчисления состоит из трёх
синтаксических категорий – процессов P, объявлений D и связок AJ/SJ. Кроме
того, также требуется, чтобы определения методов в связках AJ/SJ не повторялись.
Из табл.1 видно, что синтаксис ||-исчисления (а далее будет показано, что и
семантика тоже) является дальнейшей модификацией формального исчисления
для языка MC# 2.0, описанного в работе Y.Serdyuk, “A formal basis for the MC#
programming language”. Основное отличие заключается в том, что вместо каналов
здесь используются асинхронные методы, вместо хендлеров – синхронные
методы, а вместо отправки сообщений – вызовы методов.
В общем случае существует два способа определения операционной
семантики (operational semantics) для параллельных исчислений:
1. с помощью описания «химических правил» в стиле «абстрактной
химической машины»;
2. с помощью описания абстрактных операционных семантик, которые
используют отношение структурной конгруэнции.
Химические абстрактные машины более приближены к практическим
реализациям распределенных вычислительных систем, а потому более
предпочтительны, чем абстрактные операционные семантики. Для описания
семантики ||-исчисления мы будем использовать модификацию распределенной
рефлексивной химической абстрактной машины, которую для краткости назовем
DRCHAM (сокращение от distributed reflexive chemical abstract machine).
Определение 5. Химическое решение CS – это отношение S[D├P], состоящее
из множества узлов (сайтов) S, каждый из которых связан с множеством
D  D1 ,..., Dn  объявлений исчисления и множеством P  P1 ,..., Pn  исполняемых
процессов.
Химические решения и DRCHAM получили свои названия из-за близкой
параллели, которую можно провести между операционной семантикой и
правилами реакций в молекулярной химии.
13
Используя «химические» метафоры, можно привести следующие аналогии
для ||-исчисления:
~
 Вызов функции F  f E  является атомом, в то время как определение
функции f является валентностью.
 Параллельная композиция F1 | F2 | ... | Fn атомов является простейшей
молекулой; любой другой процесс P является сложной молекулой.
 Правило J ‣ P является правилом реакции, которое определяет, как простые
молекулы могут реагировать и превращаться в новые, более сложные
молекулы. В общем случае, данное правило определяет образец реакции,
который базируется только лишь на валентностях реагирующих молекул. В
этом виртуальном мире не соблюдается закон сохранения массы: P может
быть каким угодно большим или малым.
 Всевозможные множества, составляющие распределенную рефлексивную
химическую абстрактную машину, являются множествами химических
решений; причем изменение порядка следования элементов в этих
множествах является Броуновским движением.
Машина DRCHAM является «рефлексивной», потому что её состояние на
каждом из сайтов из множества S содержит не только решение, состоящее из
молекул, которые могут взаимодействовать, но также и множество правил,
которые определяют эти взаимодействия. Более того, это множество может
динамически расширяться новыми правилами для новых валентностей (однако,
правила для фиксированного набора валентностей не могут быть изменены или
расширены).
В отличие от машины RCHAM, использовавшейся при описании joinисчисления, машина DRCHAM является «распределенной», т.к. описывает
состояние определений и правил на множестве сайтов S.
В абстрактных химических машинах можно выделить два вида
вычислительных правил:
 Правила редукции (обозначаются оператором ‘→’) описывают фактические
«химические» взаимодействия между молекулами. Данный вид реакции
необратим, если нет соответствующего обратного правила редукции.
 Правила разогрева (heating steps, обозначаются оператором ‘⇀’) описывают,
как молекула взаимодействует с химическим решением. Шаги разогрева
всегда можно отменить с помощью соответствующих правил охлаждения
(cooling steps, обозначаются оператором ‘⇁’). Часто эти виды правил
совмещают – в этом случае используется оператор ‘⇌’.
14
Для описания операционной семантики ||-исчисления необходимо ввести ряд
обозначений:
1. P {E} - обозначает процесс P, в котором встречается выражение E, а
выражение P {E2 / E1} определяет процесс, получающийся при замене E1 на
E2 в процессе P.
2. o = {J ‣ P} - обозначает объявление объекта, в котором обязательно
содержится объявление J ‣ P.
3. ~x ⇒ ~y - обозначает подстановку, которая заменяет каждое вхождение ~xi
соответствующим значением ~yi (при условии, что длины векторов ~x и ~y
совпадают).
4. Выражение вида Os( ~x ) называется локализованным объектом,
относительно сайта s, что означает, что объект был создан и находится на
узле s. Асинхронные и синхронные методы локализованных объектов
относительно сайта s будем называть локализованными методами,
относительно сайта s.
5. Пусть  и  – некоторые подстановки, удовлетворяющие условию
domain( )  domain( )   , где domain(x) – область определения x. Тогда
выражение    означает новую подстановку с областью определения
domain(   )  domain( )  domain( ) , в которой для каждого имени u верно
следующее:
 (u ), если u  domain( )

u (   )    (u ), если u  domain( )
 u, в остальных случаях

Операционная семантика ||-исчисления задается правилами, рассмотренными
ниже. В каждом правиле отображаются только те процессы и объявления, которые
затрагиваются в данном вычислительном шаге:
15
NULL:
s [├ 0] ⇌ s [├]
PAR:
s [├ P1 || P2 ] ⇌ s [├ P1, P2 ]
TOP:
s [ ⊤├ ] ⇌ s [├]
AND:
s [ o.D1 & o.D2├ ] ⇌ s [ o.D1, o.D2├]
DEF:
s [├ obj o in P ] ⇌ s [ osσ├ Pσ ]
σ - присваивает свободные имена (относительно сайта s) объектам,
описанным в o
6. SYNC-CALL:
s [o = {sm( ~x ):P}├ o.sm( ~y ) ] → s [o = {sm( ~x ):P}├ P( ~x ⇒ ~y )]
7. ASYNC-CALL:
s [o = {AJ s ‣ P}├ o.AJ σ ] → s [o = {AJ s ‣ P}├ P σ ]
где σ – подстановка, присваивающая свободные имена (относительно
сайта s) объектам, описанным в асинхронной связке AJ
8. JOINT-CALL:
s [o = {sms( ~x ) & AJ s ‣ return E}├ P{sm( ~y )}, o.AJ σ ] →
s [o = {sms( ~x ) & AJ s ‣ return E}├ P{E( ~x ⇒ ~y ○ σ / sm( ~y )}]
где σ – подстановка, присваивающая фактические значения
формальным параметрам
9. MOVABLE-CALL:
s [ o s ├ o.mm(x) → r] ∥ r [├] ⇌ s [ o s ├] ∥ r [ o s σ├(o.mm(x)) σ]
где σ – подстановка, присваивающая свободные имена (относительно
сайта r) объектам, описанным в o
10.REMOTE-SYNC-CALL: s [o = Ds├] ∥ r [o = Ds├ P {o.sm( ~x )}] ⇌
s [o = Ds; o2=Fr├ o2.am(o.sm( ~x ))] ∥r [o = Ds;o2=Fr ├ P {o2.sm() /
o.sm( ~x )}]
где r ≠ s и определение D = sm( ~x ) & AJ ‣ return E с некоторыми AJ и
E, а o2 – это новый объект с объявлением F = sm() & am( ~x )‣return E на
сайтах s и r
11.REMOTE-ASYNC-CALL:
s [o = Ds├] ∥ r[o = Ds├ o.am( ~x )] ⇌
s [o = Ds├ o.am( ~x )] ∥ r[o = Ds├]
где r ≠ s и объявление D содержит асинхронную связку AJ‣P или
синхронную связку SJ ‣ return E, где AJ и SJ соответственно содержат
асинхронный метод am
Как уже было сказано выше семантика ||-исчисления является модификацией
формального исчисления для языка MC# 2.0, описанного в работе Y.Serdyuk, “A
formal basis for the MC# programming language”. Основное отличие заключается в
том, что вместо каналов здесь используются асинхронные методы, вместо
хендлеров – синхронные методы, а вместо отправки сообщений – вызовы методов.
1.
2.
3.
4.
5.
16
Рассмотрим пример редукции процесса. Пусть P – процесс, запуск которого
производится с узла s из некоторой начальной конфигурации s [├ P] ∥ r [├], где s
и r – названия узлов, а сам процесс P описывается следующим образом:
P
=
obj o1 = D1; o2 = D2 in o1.mm( o1.am ) → r ∥ o2.print( o1.sm() ),
где
D1
=
mm(am) : am( “Hello world!”), sm() & am(x) ‣ return x
D2
=
sprint(x) ‣ 0
Тогда можно привести следующую последовательность редукций:
s [├ P] ∥ r [├ ] ≡
s [├ obj o1 = D1; o2 = D2 in o1.mm(o1.am) → r ∥o2.sprint( o1.sm() )] ∥ r [├ ] ⇌ DEF
s [ o1  D1s , o2  D2s ├ o1.mm(o1.am) → r ∥ o2.sprint( o1.sm() )] ∥ r [├ ] ⇌ PAR
s [ o1  D1s , o2  D2s ├ o1.mm(o1.am) → r , o2.sprint( o1.sm() )] ∥ r [├ ] ⇌ MOVABLECALL
s [ o1  D1s , o2  D2s ├ o2.sprint(o1.sm())] ∥ r [ o1  D1s ├ o1.mm(o1.am)]  mm(am)
s [ o1  D1s , o2  D2s ├ o2.sprint(o1.sm())] ∥ r [ o1  D1s ├ o1.am(“Hello world!”)]
⇌ REMOTE ASYNCCALL
s [ o1  D1s , o2  D2s ├ o2.sprint(o1.sm()), o1.am(“Hello world!”)] ∥ r [ o1  D1s ├] ⇌ JOINT CALL
s [ o1  D1s , o2  D2s ├ o2.sprint( “Hello world!”)] ∥ r [ o1  D1s ├] ⇌ SYNCCALL
s [ o1  D1s , o2  D2s ├ 0] ∥ r [ o1  D1s ├] ⇌ NULL
s [ o1  D1s , o2  D2s ├] ∥ r [ o1  D1s ├]
Данный пример многошаговой редукции равносилен выполнению следующей
программы на языке Parallel C#:
class MyProgram {
// Определение D1
movable mm( () => async am ) { am(“Hello world”); }
string sm() & async am(string x) { return x; }
// Определение D2
void sprint(string x) {
// Просто ничего не делаем…
}
// Запуск процесса P
void P() {
mm(am); sprint(sm);
}
}
17
Представленное в работе ||-исчисление является удобным средством для
создания эмуляторов и распределенных систем исполнения для различных
вычислительных платформ.
В разделе 2.11 произведен детальный анализ модели языка на примерах
программ (вычисление чисел Фибоначчи, решето Эратосфена, перемножение
матриц и поиск слов в больших текстах), написанных на языке Parallel C#.
Приведен полный код программ, а также замеры производительности на
кластерных установках.
На рис. 3 и рис. 4 приведены графики с замерами производительности
тестовых программ, написанных на языке Parallel C#: перемножение матриц и
поиск слов в больших текстах.
100.00
90.00
Время (секунд)
80.00
70.00
60.00
50.00
40.00
30.00
20.00
10.00
0.00
500
600
700
800
900 1000 1100 1200 1300 1400 1500
Размер матриц
C#
Parallel C#
Рис. 3 Перемножение матриц на одном и двух ядрах процессора Intel Core 2 CPU 6400
@2.13GHz
18
800
700
Время (секунды)
600
500
400
300
200
100
0
1
2
4
8
16
32
Количество процессоров
Рис. 4 Поиск 32 слов в тексте, объёмом 64 Mb
В ТРЕТЬЕЙ ГЛАВЕ описываются особенности практических реализаций
систем исполнения, основанных на описанном ||-исчислении:
1. Parallel C# Many Core Edition - система программирования, позволяющая
компилировать и исполнять программы, написанные на языке
программирования Parallel C# в локальном режиме на Windows-машинах
(в т.ч. на многоядерных машинах). Данная версия в основном
предназначена для написания и отладки параллельных программ на
локальных машинах программистов.
2. Parallel C# Cluster Edition - система программирования, позволяющая
компилировать и исполнять программы, написанные на языке
программирования Parallel C# на Linux-кластерах.
Реализация Parallel C# состоит из компилятора и системы исполнения.
Компиляция программ, написанных на языке Parallel C#, производится в 2 стадии:
1. Трансляция программы из языка Parallel C# в язык C#;
2. Компиляция сгенерированных C#-файлов стандартным C# компилятором
(csc для платформы Microsoft .Net и gmcs для платформы Mono), с
подключением библиотек распределенной системы исполнения.
В качестве инструментов для практической реализации компилятора были
выбраны GPLEX (генератор лексеров) и GPPG (генератор LALR(1) парсеров).
Данный выбор был обусловлен тем, что эти инструменты генерируют код на
19
языке C#, а также упрощают задачу интеграции со средой разработки Microsoft
Visual Studio (с помощью дополнительного инструмента - Managed Babel).
Трансляция программ с языка Parallel C# в язык C# состоит из нескольких
этапов:
1. Разбиение программы на токены с помощью лексера
2. Разбор потока токенов с помощью парсера и генерация абстрактного
синтаксического дерева (AST)
3. Двухфазная трансформация AST-дерева с помощью паттерна IVisitor
4. Генерация кода на языке C# (также с помощью паттерна IVisitor).
В разделах 3.1-3.2 детально описываются грамматика языка Parallel C#, а
также принципы трансляции основных языковых элементов в язык низшего
уровня (в данном случае – C#).
Раздел 3.3 посвящен вопросам реализации распределенной системы
исполнения для кластерных архитектур на базе Linux. На рис. 5 показана общая
схема кластеров, где выделяются одна главная (фронтальная) машина, с которой
запускаются все пользовательские приложения, а также рабочие узлы, на которых
и производится основная часть вычислений.
Пользовательский
компьютер
Work Node [a]
RSH/SSH
соединение
Фронтальная
машина
Локальная
сеть
WAN
Копия пользовательской
программы [1]
Communicator [1]
Копия пользовательской
Узел [а] программы [n]
Communicator [n]
...
Work Node [z]
Пользовательский
компьютер
XTerminal
Менеджер распределения
ресурсов
Пользовательская программа [0]
Communicator [0]
Узел [z]
Копия пользовательской
программы [k]
Communicator [k]
Рис. 5 Схема кластера
Доступ к фронтальной машине возможен из глобальной сети посредством
SSH. На фронтальной машине запускается менеджер распределения ресурсов,
основной функцией которого является планирование и распределение запросов на
исполнение перемещаемых методов. На рабочих узлах запускаются копии
программы WorkNode, единственной функцией которой является запуск и
остановка копий клиентских приложений на узлах.
20
Пользовательское приложение
Менеджер распределения ресурсов
Потоки выполнения
перемещаемых методов
Обслуживающие
потоки
Входящие
сообщения
Communicator
Таблица
объектов
Входящие
сообщения
Перемещаемые
методы
...
...
Nodes
Пользовательские объекты и потоки
Пул потоков
Apps
Проксивызовы
Очереди
переданных параметров
прокси-вызовов
Рис. 6 Схема ПО главного узла
Каждый из узлов кластера должен быть доступен с другого узла кластера
посредством RSH/SSH. Для того чтобы какую-либо программу можно было
запустить на рабочих узлах, необходимо, чтобы файлы сборки этой программы
находились на всех узлах кластера. Этого можно достичь либо предварительным
копированием файлов сборок на все узлы, либо с помощью сетевой файловой
системы (NFS). Пути к пользовательским программам должны совпадать на всех
узлах - это ограничение легко реализуется с помощью файловой системы NFS.
Каждое пользовательское приложение на рабочих узлах исполняется в
отдельном процессе. При этом на одном рабочем узле может быть запущено
несколько копий процесса пользовательского приложения – таким образом можно
эмулировать виртуальные узлы кластера. Выбор архитектуры, в которой
отдельные пользовательские приложения обслуживаются в отдельных процессах
(а не в рамках одного глобального приложения-контейнера), был обусловлен
вопросами устойчивости системы исполнения от перегрузок и безопасности.
В каждой копии пользовательского приложения запускается коммуникатор сервер, который принимает от других узлов команды на определенном, случайно
сгенерированном порту, разбирает заголовки команд и выполняет их.
Коммуникатор содержит необходимую логику для принятия и запуска
перемещаемых методов, обслуживания прокси-вызовов и т.д.
При передаче прокси-метода в другой метод автоматически создается объектобёртка, который регистрируется в специальной хеш-таблице коммуникатора.
Именно по этой таблице коммуникатор находит зарегистрированные проксиобъекты, когда приходят соответствующие команды.
21
ОСНОВНЫЕ РЕЗУЛЬТАТЫ
1.
2.
3.
4.
Предложена формализованная языковая модель (||-исчисление), в которой
впервые скомбинированы функциональные типы/функции высшего
порядка и связки асинхронных и синхронных методов, служащих
средством синхронизации потоков. Данная модель позволяет расширять
существующие объектно-ориентированные языки до языков со
встроенной поддержкой параллельного программирования (в т.ч.
распределенного).
Разработаны правила трансляции новых синтаксических конструкций в
языки низшего уровня и представлена в качестве демонстрации
практическая реализация данных правил на примере языка Parallel C#
(расширение существующего языка C#). Стоит отметить, что с помощью
данных конструкций можно легко расширить многие другие языки
программирования, например, Java, Nemerle и др., т.е. представленная
модель рассчитана не только на один конкретный язык
программирования.
Разработаны компилятор и две системы исполнения для языка Parallel C#
– для многопроцессорных и кластерных архитектур. Реализованы
тестовые программы и произведены замеры производительности этих
программ на кластере, показавших приемлемый уровень ускорения на
разном числе процессоров.
Разработанная в диссертации модель расширения существующих языков
программирования для поддержки параллельного программирования
позволяет повысить эффективность работы программистов при написании
параллельных программ за счет компактного, удобного и понятного
синтаксиса, а также автоматической генерации кода при трансляции в
языки более низкого уровня.
Публикации автора по теме диссертации.
[1] Гузев, В.Б. Parallel C#: The usage of chords and higher-order functions in
the design of parallel programming languages / В.Б. Гузев // In
proceedings of PDPTA’08 – The 2008 International Conference on Parallel
and Distributed Processing Techniques and Applications. – Las Vegas,
Nevada, USA. – 2008. – С. 833-837.
[2] Гузев, В.Б. Использование связок и функций высшего порядка для
разработки языков параллельного программирования. / В.Б. Гузев //
Труды XLIV Всероссийской Конференции по Проблемам
22
[3]
[4]
[5]
[6]
[7]
Математики, Информатики, Физики и Химии, секция "Программные
Системы". – Москва: Российский Университет Дружбы Народов. –
2008. – С. 5-14.
Петров, А.В. MC# – универсальный язык параллельного
программирования. / А.В. Петров, В.Б. Гузев // Журнал
"Информационные технологии". – 2008. – №4. – C. 29-32.
Сердюк, Ю.П. MC# Grid System: подход к Grid-вычислениям на
основе языка параллельного, распределенного программирования. /
Ю.П. Сердюк, В.Б. Гузев. // Труды Всероссийской научной
конференции "Научный сервис в сети Интернет: технологии
распределенных вычислений". – Новороссийск. – 2005. – С. 41-43.
Гузев, В.Б. Решение задач обработки изображений в реальном
времени на языке параллельного программирования MC#. / В.Б. Гузев,
А.И. Молодченков, Ю.П. Сердюк. // Труды II-го Белорусского
космического конгресса. – Минск. – 2005. – C. 173-177.
Сердюк, Ю.П. Asynchronous Parallel Programming Language Based on
the Microsoft .NET Platform. / В.Б. Гузев, Ю.П. Сердюк // Proc. 7th
International Conference PACT'2003. – Нижний Новгород: Lecture Notes
in Computer Science, v. 2763. – 2003, Lecture Notes in Computer Science.
– С. 236-243.
Сердюк, Ю.П. MC#: An Asynchronous Parallel Programming Language
for Cluster and GRID-Architectures. / В.Б. Гузев, Ю.П. Сердюк, А.М.
Чудинов // Proc. of C# and .NET Technologies'2003, 1st International
Workshop on C# and .NET Technologies on Algorithms, Computer
Graphics, Visualization, Distributed and WEB Computing. – University of
West Bohemia. Plzen, Czech Republic – 2003. – Volume 1, Number 1-3 –
С. 21-24.
Личный вклад автора. В совместных публикациях по теме [4,5,6,7]
автору принадлежат создание алгоритмического и программного
инструментария (системы исполнения и частично компилятора),
разработка тестовых примеров и проведение вычислительных
экспериментов. В публикации [3] автору не принадлежит раздел,
описывающий пример с алгоритмом MapReduce. Во всех совместных
работах автор участвовал в постановке задач и интерпретации результатов.
23
Download