Сравнение языков параллельного программирования

реклама
Сравнение языков
параллельного
программирования
• Erlang
• Chapel
Подходы к разработке
параллельных программ
•
Использование библиотек для существующих
языков программирования – MPI для C и Fortran для
систем с распределенной памятью
•
Использование надъязыковых средств (директив,
комментариев) – OpenMP для C и Fortran для систем
с общей памятью
•
Расширение существующих языков
программирования – например, UPC
•
Создание новых параллельных языков
программирования – например, Chapel, X10,
Fortress,…
Модели программирования
- процесс (нить)
- адресное пространство
Передача
сообщений
Разделяемая
память
Разделенное
глобальноадресуемое
пространство
(PGAS)
PGAS модель
Th0
Thn-2
Thn-1
• Параллельные нити с
разделенной общей памятью
• Раздел памяти Мi
соответствует нити Thi
• Плюсы:
М0
…
Мn-2
Мn-1
- Просто передавать данные
- Распределение данных
упрощено, т. к. есть общее
адресное пространство
• Минусы:
- процесс (нить)
- адресное пространство
- потоки данных
- Распределение вычислений и
синхронизация по прежнему
за программистом
- Недостаточно прозрачная
распределенность локальных
и общих данных
Erlang
• Разработчик: Ericsson Computer Science
Laboratory
• Появился в 1987 году (open source с 1998)
• Релиз: Erlang/OTP R13B04 (24 февраля 2010)
• Парадигма: функциональное программирование
Синтаксис
Синтаксис унаследован от Prolog.
Поддерживает:
• модули;
• полиморфные функции;
• анонимные функции;
• условные конструкции;
• структуры;
• обработку исключений;
• оптимизацию хвостовой рекурсии.
Синтаксис
Основные конструкции:
• числа;
• переменные;
• атомы;
• кортежи;
• списки;
• строки;
• бинарные данные.
2, 5.5, 2#101
X, Y, Z
red, green, blue
{red, 255}
[2, red, {red,255}, [1,2]]
“Hello, world!”
<<104,101,108,108>>
Синтаксис
Пример программы:
-module(prog).
-export([fac/1]).
fac(1) ->
1;
fac(N) ->
N * fac(N - 1).
Запуск:
5> c(prog).
{ok, prog}
6> prog:fac(4).
24
Работа с процессами
Модель легковесных процессов.
• Erlang использует легковесные процессы, не
затрагивающие потоки операционной системы.
• Принцип работы процесса «let it crash» («пускай
падает»).
• Процессы дёшевы, создание процесса занимает не
больше ресурсов, чем вызов функции.
Работа с процессами
Асинхронный обмен сообщениями .
Единственным способом взаимодействия процессов
является асинхронный обмен сообщениями. Процесс
имеет свой «почтовый ящик», откуда по очереди читает
сообщения, сопоставляя их с шаблоном. Если ни один
шаблон не подходит, сообщение пропускается.
После отправки сообщения процесс сразу продолжает
работу, не дожидаясь подтверждения.
Работа с процессами
• Создание процесса
Pid = spawn (fun operate/0)
spawn(M,F,A) %модуль, функция, аргументы
• self() - PID текущего процесса
• Убиение процесса
exit(Pid, Reason)
• Посылка сообщения процессу
Pid ! msg
• Именные процессы
register(atom, Pid) %присвоение процессу имени
whereis(atom) -> Pid %получение PID по имени
atom ! Msg %отправка сообщения по имени
Работа с процессами
-module(prog1).
-export([start/0, say_something/2]).
say_something(What, 0) ->
done;
say_something(What, Times) ->
io:format("~p~n", [What]),
say_something(What, Times - 1).
start() ->
spawn(tut14, say_something, [hello, 3]),
spawn(tut14, say_something, [goodbye, 3]).
Результат:
> prog1:start().
hello
goodbye
<0.63.0>
hello
goodbye
hello
goodbye
Работа с процессами
-module(prog2).
-export([start/0, ping/2, pong/0]).
ping(0, Pong_PID) ->
Pong_PID ! finished,
io:format("Пинг завершил
работу~n", []);
ping(N, Pong_PID) ->
Pong_PID ! {ping, self()},
receive
pong ->
io:format("Пинг получил
понг~n", [])
end,
ping(N - 1, Pong_PID).
pong() ->
receive
finished ->
io:format("Понг завершил
работу~n", []);
{ping, Ping_PID} ->
io:format("Понг получил
пинг~n", []),
Ping_PID ! pong,
pong()
end.
start() ->
Pong_PID = spawn(prog2, pong,
[]),
spawn(prog2, ping, [3, Pong_PID]).
Работа с процессами
Вывод пинг-понга:
2> prog2: start().
<0.36.0>
Понг получил пинг
Пинг получил понг
Понг получил пинг
Пинг получил понг
Понг получил пинг
Пинг получил понг
Пинг завершил работу
Понг завершил работу
Работа с процессами
Распределенные вычисления.
• Запущенный экземпляр эмулятора Erlang называется
узлом (node). Узел имеет имя и «знает» о
существовании других узлов на данной машине или в
сети. Создание и взаимодействие процессов разных
узлов не отличается от взаимодействия процессов
внутри узла. Для создания процесса на другом узле
процессу достаточно знать его имя и, без особых на
то оснований, он может не интересоваться
физическим расположением взаимодействующего с
ним процесса.
• Чтобы дать узлу имя:
erl -sname my_name
Работа с процессами
Распределенные вычисления. Пинг-понг на двух узлах.
-module(prog3).
-export([start_ping/1, start_pong/0, ping/2,
pong/0]).
ping(0, Pong_Node) ->
{pong, Pong_Node} ! finished,
io:format("Пинг завершил работу~n", []);
ping(N, Pong_Node) ->
{pong, Pong_Node} ! {ping, self()},
receive
pong ->
io:format("Пинг получил понг~n", [])
end,
ping(N - 1, Pong_Node).
pong() ->
receive
finished ->
io:format("Понг завершил
работу~n", []);
{ping, Ping_PID} ->
io:format("Понг получил пинг~n", []),
Ping_PID ! pong,
pong()
end.
start_pong() ->
register(pong, spawn(prog3, pong, [])).
start_ping(Pong_Node) ->
spawn(prog3, ping, [3, Pong_Node]).
Работа с процессами
Запуск пинг-понга на двух машинах:
comp1> erl -sname ping
Erlang (BEAM) emulator version 5.2.3.7
[hipe] [threads:0]
comp2> erl -sname pong
Erlang (BEAM) emulator version
5.2.3.7 [hipe] [threads:0]
Eshell V5.2.3.7 (abort with ^G)
Eshell V5.2.3.7 (abort with ^G)
(ping@comp1)1>tut17:start_ping(pong@
comp2).
<0.37.0>
Пинг получил понг
(pong@comp2)1>prog3:start_pong().
true
(pong@gollum)2>
Понг получил пинг
Пинг получил понг
Понг получил пинг
Пинг получил понг
Понг получил пинг
Пинг завершил работу
Понг завершил работу
Подитог. Erlang.
•
•
•
•
•
Функциональный
Параллелизм и прозрачная распределенность
Модель легковесных процессов.
Обмен сообщениями.
Хорошо масштабируемый.
Chapel
• Разработчик: Cray Inc.
• Появился в 2006 году
• Релиз: Сhapel-1.2.0 (29 октября 2010)
• Парадигма: императивное программирование
Chapel
Язык Chapel (Cascade High Productivity Language) был
разработан в рамках проекта «Каскад», для участия в
программе DARPA Высокопродуктивные компьютерные
системы(HPCS).
Целью создания было повышение продуктивности
распараллеливания вычислений, путем реализации
наиболее высокого уровня выражения, нежели это
позволяют существующие языки.
Продуктивность = Производительность +
Программируемость + Переносимость + Надежность
Синтаксис
В основном синтаксис заимствован из C и Modula.
Оказали влияние:
• ZPL, HPF: параллелизм данных, множества
индексов, распределенные массивы
• CRAY MTA C/Fortran: параллелизм команд,
синхронизация
• CLU, Ruby, Python: итераторы
• ML, Scala, Matlab, Perl, Python, C#: неявные типы
• Java, C#: ООП, безопасность типов
• C++: шаблоны
Поддержка параллельности
Язык Chapel был создан на основе модели
разделенного глобально-адресуемого пространства
(Partitioned Global Address Space).
• Поддерживает мнопоточность, явные механизмы для
работы с локальностью;
• Имеет средства для распределения массивов по
вычислительным узлам системы
• Поддерживает как параллелизм по данным, так и
параллелизм задач.
Поддержка параллельности
Управление локальностью.
• Язык Chapel обеспечивает доступ пользователей к
виртуальным единицам локальности, называемые
локалями (locale).
• Каждое выполнение программы привязывается к
некоторому набору локалей, которые отображаются
операционной системой на физические сущности,
такие как вычислительные узлы.
• У пользователя есть механизмы, для распределения
данных по локалям.
Поддержка параллельности
Параллелизм задач: Оператор begin
• Синтаксис:
begin stmt
• Семантика:
o Создает параллельную задачу для выполнения stmt
o Выполнение программы родителя не останавливается
• Пример:
begin writeln(“hello world”);
writeln(“good bye”);
• Вывод неоднозначен.
Поддержка параллельности
Параллелизм задач: Оператор cobegin
• Синтаксис:
cobegin { stmt-list }
• Семантика:
o Создает параллельную задачу для каждого оператора stmt-list
o Синхронизация при завершении блока
• Пример:
cobegin {
consumer(1);
consumer(2);
}
Поддержка параллельности
Параллелизм задач: Оператор coforall
• Синтаксис:
coforall index-expr in iterator-expr { stmt }
• Семантика:
o Порождает параллельную задачу для каждой итерации
цикла
o Синхронизация при завершении цикла
• Пример:
begin producer();
coforall i in 1..numConsumers {
consumer(i);
}
Поддержка параллельности
Редукция данных: Оператор reduce
• Синтаксис:
reduce-op reduce iterator-expr
• Семантика:
o Применяет для каждого элемента данных операцию
reduce-op
• Пример:
bigDiff = max reduce [i in 1..100] abs(A(i) – B(i);
Поддержка параллельности
Работа с локалями. Пример.
var x, y: real; // x и y на locale 0
on Locales(1)
{ // migrate task to locale 1
var z: real; // z на locale 1
z = x + y; // удаленный доступ к x и y
on Locales(0) do // возврат на locale 0
z = x + y; // удаленный доступ к z
// возврат на locale 1
on x do // переход на locale 0
z = x + y; // удаленный доступ к z
// переход на locale 1
} // возврат на locale 0
Подитог. Chapel.
• Модель разделенной глобально-адресуемой памяти
• Виртуальные единицы локальности, отображаемые
на реальные вычислительные узлы
• Поддержка одновременно параллелизма по данным
и по командам
• Возможность настроить код под определенную
машину (выравнивание данных в локалях,
переброска данных)
Спасибо за внимание.
Скачать