Введение в эксперементальный язык программирования Axum

четверг, 28 января 2010, Kos

Мотивация

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

Введение

Axum - экспериментальный язык, созданный Microsoft Research, для упрощения написания программ с использованием асинхронного программирования. Поскольку язык экспериментальный, то для него нет коммерческой поддержки и возможны не информативные ошибки компилятора. Также не все элементы спецификации реализованы и нет специального отладчика для axum, правда с ним работает отладчик C# -но некоторые конструкции ему не понятны. До знакомства с Axum я познакомился с языком Erlang. Эрланг "знаменит" благодаря своей парадигме легковесных процессов или SIP (Semi-Integrated Processes), надёжности и мощности платформы OTP (Open Telekom Platform). Легковесный процессы не являются процессами ОС, они даже не являются потоками с её точки зрения, переключение между ними осуществляется виртуальной машиной эрланг. Но всё же они называются процессами - потому что их память изолирована друг от друга, и общаются они между собой только при помощи асинхронных сообщений. 

Идеология

Язык очень экспериментальный, видимо создатели решили испытать на совместимость все прогрессивные концепции программирования, которые им понравились. Например  мультиагентное программирование, асинхронное программирование. Кроме того, каналы, которые являются частью языка, позволяют  реализовывать ленивые вычисления.  От эрланг новый язык выгодно отличается статической типизацией и использованием .Net CLR (разумеется это лишь часть отличий).

Сравнение с C#

Язык много унаследовал от C#, по крайней мере так кажется при первом взгляде - это впечатление объясняется обилием фигурных скобок, хотя действительно есть много общих выражений концептуально языки разные - в axum нет возможности описывать классы и там нет ничего подобного им. Сравним два языка более детально :


Общее с C#

Не поддерживаемые элементы C#

Уникальные особенности axum

Все выражения  и операторы C# 3.0

Классы, интерфейсы и структуры

Агенты и домены

LINQ (не реализовано)

Объявление операторов

Каналы

Объявление полей (в доменах) и

методов(в агентах)

Свойства

Схемы

Делегаты

Константные поля и переменные

Сети

Перечисляемые типы

Статические поля и методы

Interleaved control flow

Пример программы

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

using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;
using System.ServiceModel.Channels;
namespace ConsoleApplication1
{
    channel Task
    {
        input int Num1;
        input int Num2;
        output int Sum;
    }
    public domain Program
    {
       agent MainAgent1 : channel Microsoft.Axum.Application
        {
            public MainAgent1()
            {
                String [] args = receive(PrimaryChannel::CommandLine);
                var cmp = new InprocCommunicationProvider();	 
				var chanColl = new Task[30000]; 
                var ret = new int[3000000];
                IHost hst = new InprocHost();
                for(int i = 0; i < 30000; i++)
                {
                    var name = "a"+i.ToString();
                    Program.DefaultHost.Host<Smith>(name);
					var chan = cmp.Connect<Task>(name); 
				    chanColl[i] = chan;
                    chanColl[i]::Num1 <-- 123;
                }
                for(int i = 0; i < 30000; i++)
                {
                    chanColl[i]::Num2 <-- 8124;   
			    }
                for(int i = 0; i < 30000; i++)
                {
                 ret[i] = receive(chanColl[i]::Sum);
                    Console.WriteLine(ret[i]);
                }
                PrimaryChannel::Done <-- Signal.Value;
            }
        }
        public agent Smith: channel Task
        {
            public Smith()
			{ 
				int result1 = receive(PrimaryChannel::Num1);  
				int b =	receive(PrimaryChannel::Num2); 
				//for(int i = 0; i < b; i++ )
                {
                    result1+=b;//i;
                }
                PrimaryChannel::Sum <-- result1; 
			} 
        }
    }
}

              

Уверен, Вы заметили, что язык очень похож на широко известный C#, но есть и масса отличий. Рассмотрим элементы синтаксиса axum ( только те, что использованы в данном примере - основные, в спецификации есть намного больше рюшечек, но часть из них даже не реализована).

0) Самое простое - пересылка сообщений в точку взаимодействия :

ИмяЭкземпляраКанала::ИмяТочкиВзаимодействия <-- 123;

1) Каналы используются в языке для взаимодействия между агентами и  доменами.

    channel ИмяТипаКанала

    {

        input Тип ИмяВхода;

        output Тип ИмяВыхода;

    }

В указанном канале есть две точки взаимодействия (Interaction points) -для ввода значения и вывода.

2) Агенты выполняются в рамках доменов, домены могут выполняться на разных машинах, или в разных процессах на одной машине.

    public domain ИмяДомена

    {

       agent ИмяОсновногоАгентаДомена: channel ИмяТипаОсновногоКаналаАгента

        {

            public ИмяОсновногоАгентаДомена ()

            {

              //Это конструктор агента

              //Посылаем в основной канал, в точку взаимодействия по имени Done

              // значение с которым завершилась работа агента

              //Это аналог возврата значения при выходе

                PrimaryChannel::Done <-- Signal.Value;          

             }

        }

    }

 

3) Метод receive получает данные из канала.  

String [] args = receive(PrimaryChannel::CommandLine);

4) Основной канал агента PrimaryChannel - с этим каналом агент живёт всю свою жизнь.

5) Каждый агент размещается в рамках хоста - есть WCFHost, в данном примере агент размещается в родительском процессе. При создании агента он получает уникально имя, если вы это делает автоматически, то его нужно генерировать.

                IHost hst = new InprocHost();

                for(int i = 0; i < 10000; i++)

                {

                    var name = "a"+i.ToString();

                    Program.DefaultHost.Host<Smith>(name);

                     var chan = cmp.Connect<Task>(name);

                     chanColl[i] = chan;

                }

Аналогичная программа на Эрланг
-module(main).
-export([main/0,smith/1,start/2,send/1,wait/0]).

main() -> List = start(20000,[]),
send(List),
wait().

start(0,List)->
	List;
start(N,List)->X = spawn(main,smith,[123]),
			   NewList = [X|List],
			   start(N-1,NewList).

send([])->
	[];
send([Elem|List])->
	Elem ! {8124,self()},
	send(List).

wait()->
receive
  R ->
	  io:format("~w ~n",[R]),
	  wait()
after 1000 ->
            io:format("End~n", [])
end. 

smith(A)->
	receive
		{B,Papa}->
			Papa ! A+B
	end.

Colored with dumpz.org

 

Сравнение производительности 

 

Время выполнения(сек)

Количество потоков

Axum

Erlang SMP

10000

4

8

20000

8

14

30000

12

21

100000

38

отказ

1000000

Более 8 минут

отказ

Update : изменил параметры компилятора эрланг (добавил флаг native), теперь тест с 30 000 потоков выполняется за ~13 секунд, это означает что тестируется скорость ввода-вывода (((

Признаю, тест производительности таких языков должен был бы скорее тестировать быстродействие при коммуникациях между легковесными процессами нежели время вычислений. Данный тест указывает нам, что Axum позволяет создавать большее количество легковесных процессов. Преимущество в быстродействии скорее всего объясняется общим для всех процессов сборщиком мусора (в эрланг у каждого легковесного процесса сборка мусора происходит отдельно - что повышает отзывчивость системы, так как при сборке мусора не блокируется работа всех процессов) и тем что axum является языком с статической типизацией. Так же следует отметить интересную особенность работы программы на эрланг : потоки были выделены очень быстро, быстро получили порцию данных и на протяжении всего времени работы программа выводила результаты разных потоков в то время как Axum 2/3 времени считал, и только после этого начнал вывод результатов - что означает что система на эрланг является более отзывчивой. Так же следует отметить то,  что программа на эрланг ровно вдвое короче аналогичной на axum.

Выводы

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

  • хотелось бы видеть поддержку автоматического разделения потоков по доступным процессорам (что-то напоминающее SMP в эрланг).
  • мало информации о распределённом программировании.

Так же ходят слухи о возможной интеграции наработок команды Axum в новые версии F#.

Компании из статьи


Microsoft Украина


Сайт:
http://www.microsoft.com/ukr/ua/

Microsoft Украина Украинское подразделение компании Microsoft.

Ищите нас в интернетах!

Комментарии

Свежие вакансии