Программист-полиглот

Параллелизм с каналами, доменами и сообщениями

Тэд Ньюард (Ted Neward)

В последней статье мы рассмотрели языка программирования Cobra объектно ориентированный язык слабо производным Python использует оба статических и динамических введите некоторые "сценарии"Основные понятия аналогичны Python и Ruby и baked оснастке модульного тестирования функций, среди прочего. После более глубокого исследования мы видели имеет значение, мы были рады узнали новый универсальный язык программирования.

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

Тщательного и тщательного читателей этот журнал будет Обратите внимание, это meme параллелизма не является один из незнакомых на эти страницы. Последние несколько лет видел множество статей по параллелизма поступают здесь и MSDN Magazine вряд ли уникален в этом отношении--блогосфере, Twitterverse и порталы Web разработчика всех rife с обсуждениями параллелизма, включая небольшое naysayers, думаю, что это самое всей параллелизма другой попытка создать проблема вне тонких воздуха. Некоторые эксперты отрасли даже прошли до сих, скажем (согласно rumor на панель обсуждений конференции OOPSLA несколько лет назад), «параллелизма является dragon, мы должны slay в ближайшие десятилетия.»

Некоторые разработчики будут интересно, что проблема действительно заключается--после всех .NET имел возможность многопоточность лет через идиому вызова асинхронного делегата (BeginInvoke и EndInvoke) и предоставляет механизмы потокобезопасности через конструкции монитора (ключевого слова lock в C#, например) и других явных параллелизма конструкции объекта (мьютекс, событий и т.п., из System.Threading.). Поэтому этот новый суетой кажется внесения горный вне molehill. Этих разработчиков бы абсолютно справа предполагается написать код, является поточно-(1) 100 процентов и (2) ведения преимущества каждой возможности для параллелизма задач или данные в своем коде путем смешивания потоков или воспользоваться потоков из пулов потоков, чтобы максимизировать использование ядер, предоставляемой базовой оборудования. (Если вы безопасный на обоих счетчиков, выберите Перейти к следующей статье журнала. Больше еще одну запись и сообщите вашей секреты.)

Многочисленные предложений для решения или по крайней мере снизить, проблема был плавающим через вселенной Microsoft, включая библиотеки параллельных заданий (TPL), расширения Parallel FX (PFX), потоки F # асинхронных операций, блокировки и управления среды выполнения (CCR) и т. д. В каждом из этих случаев решением является либо для расширения языка узла (обычно C#) в способов для предоставления дополнительных параллелизма или предоставляют библиотеки, которая может быть вызван из универсальный язык .NET. Недостатком на большинство из этих подходов однако является поскольку они зависят от семантики языка узла, выполнив правильную вещь с точки зрения параллелизма условие выбора, что разработчикам приходится явно купить в и код соответствующим образом. Это Увы означает, что может быть возможность это неправильный самое, независимо от таким образом создает параллелизма отверстие, что код может в конечном счете делятся на и создание ожидающих быть обнаружены ошибки, и это плохо. Средства разработчика не следует в идеально подходит, разрешить разработчикам сделать самое неправильный--именно платформу .NET перемещен сборщиком мусора подход, например. Вместо этого средства разработки должны вызывать разработчикам, как Rico Mariani (Microsoft Visual Studio разработчик и архитектор бывший производительности CLR) помещает его "делятся на лифта успехов"--что разработчиков обнаружить, проще сделать должно быть правильную вещь, и какие разработчики найти трудно сделать или найти невозможно сделать следует самое неправильный.

Сторону этого корпорация Майкрософт выпустила как проект incubation, новый язык, предназначенных squarely домена параллелизма, называется «Axum.» В духе из разработчиков "попадает в лифта успех"Axum не универсальный язык C# или Visual Basic, но один squarely направленные на проблемы параллелизма, целью из завершении быть частью набора языков, которые в совокупности сотрудничать для решения проблемы бизнеса. По сути Axum является отличным примером доменный язык язык, предназначенный специально для решения только один вертикальный аспект неполадки.

Как написания этой статьи Axum помечается как версия 0.2 и сведения о языке и операции Axum могут полностью изменяться, как указано заявления об отказе в начале статьи. Но между «как я пишу это"и «как чтение»Основные понятия должны оставаться довольно стабильны. Фактически эти понятия не являются уникальными Axum и находятся в ряд других языков и библиотек (включая некоторые из описанных проектов, например F # и CCR), поэтому даже если Axum сам не сделать ее широко используются, здесь идеи неоценимым думать о параллелизме. Более того основная идея--конкретного домена проблемы языка--быстро растет в "большой вещь"и стоит проверки в своей собственной справа хотя в более поздней версии фрагмент.

Начале

В настоящее время live Axum битов для загрузки на веб-семинары Microsoft узле на msdn.microsoft.com/devlabs/dd795202.aspx;необходимо выбрать по крайней мере .msi (либо для Visual Studio 2008 или бета-версии 1 для Visual Studio 2010) и Руководство программиста. После установки этих, срабатывание Visual Studio и создайте новый проект приложения консоли Axum, как показано на рис. 1.


Рисунок 1 проекта приложения консоли Axum

Замените код, показанный на рис. 2. Это Axum "Hello World"выполняет которого служит же цели, как все другие приложения Hello World: Чтобы проверить работал установки и получить основные чувство синтаксис. Предполагая, что все компилирует и запускает, мы хорошо переход.

На рис. 2 Axum "Hello World"

using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;
namespace Hello
{
public domain Program
{
agent MainAgent : channel Microsoft.Axum.Application
{
public MainAgent()
{
String [] args = receive(PrimaryChannel::CommandLine);
// TODO: Add work of the agent here.
Console.WriteLine("Hello, Axum!");
PrimaryChannel::ExitCode <-- 0;
}
}
}
}

Как можно увидеть, имеет очень reminiscent C#, слабо разложить Axum категорию языков, известные как C семейства языков синтаксис Axum: он использует фигурные скобки для обозначения области, точка с запятой для завершения операторов и т.д. Это сказал однако существуют очевидно, что несколько новых ключевых слов для получения знать (домена, агент, канал, прием, просто новичкам) плюс несколько новых операторов. Формально Axum не действительно производную C#, но подмножество Выборочный добавлены новые возможности. Axum включает все типы оператор C# 3.0 (например, лямбда-выражения и выводимые локальные переменные) и выражений (таких как алгебры вычислений и разрыв возврата и доход доход), методы, объявления полей, делегаты и типы перечисления, но оставляет классами, интерфейсами или определения структуры и значение типа оператора объявления, свойства, const полей и локальные переменные и статические поля и методы.

Что звука whooshing? Ветер, rushing за пределами вашего уши, и если вы считаете незначительные fluttering в вашей stomach, лучше. Переход за пределы cliffs является хорошей вещью.

Основные понятия и синтаксис

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

Чтобы увидеть это в действии, рассмотрим код Hello. Агент MainAgent реализует особые канал приложение канал, среда выполнения Axum понимает непосредственно--он будет обрабатывать все входящие аргументы командной строки и передать их по каналу PrimaryChannel приложения на порте CommandLines. При создании средой MainAgent использует операции получения (Axum примитив) для блокирования порта до эти аргументы будут доступны, в этот момент выполнение в конструкторе MainAgent продолжается. Среды выполнения, выполняется задание, затем блоки на порт ExitCode PrimaryChannel, являющийся сигнала завершения приложения. Тем временем выплату MainAgent через массив, печать каждый из них и после завершения отправляет порт ExitCode целочисленный литерал 0. Принимается средой выполнения, завершает процесс.

Обратите внимание, как Axum, с самого начала занимает эта идея параллельного выполнения серьезно--не только являются sheltered разработчиков от создания и обработки потоков или параллелизма и блокировки объектов, но языка Axum предполагает подход к одновременных даже для примерно так же просто, как Hello. Примерно так же просто, как Hello возможно, это потерей времени--тем не менее, большинство из нас не очень часто писать приложения так же просто, как приветствия и кто-то сделать, можно всегда небезопасной язык традиционных объектно ориентированного приложения одного потоков по умолчанию (C# или Visual Basic или любой другой сбоях на fancy).

На рис. 3 процесс приложения

using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;
namespace Process
{
public domain Program
{
agent ProcessAgent : channel Microsoft.Axum.Application
{
public ProcessAgent()
{
String [] args = receive(PrimaryChannel::CommandLine);
for (var i = 0; i < args.Length; i++)
ProcessArgument(args[i]);
PrimaryChannel::ExitCode <-- 0;
}
function void ProcessArgument(String s)
{
Console.WriteLine("Got argument {0}", s);
}
}
}
}

Hello о том, подходит Wimps

Немного более интересный пример — это приложение процесса как показано на рис. 3. В данной версии мы видим новая концепция Axum функцию. Функции отличаются от традиционные методы, компилятор Axum (по способом от ошибки компилятора) гарантирует метод никогда не изменяет внутреннее состояние агента пользователя;Другими словами функции, может не иметь побочные эффекты. Предотвращение побочные эффекты добавляет полезность Axum как понятное параллелизма язык--без побочных эффектов, становится очень сложно случайно написать код где поток изменяет состояние общей (и таким образом представляет несогласованность или неверным результатам).

Но мы еще не готово здесь. Axum требуется не только для упрощения написания кода поточно ориентированными также хочет проще написать код потока понятное. С компьютерами два и четырех основных становится более распространение и 8 и 16 основные машины видны на расщепления важно искать возможности выполнять операции параллельно. Axum делает это проще, снова, подъема диалога из потоков и предоставление некоторые конструкции более высокого уровня для работы. На рис. 4 показывает измененную версию ProcessAgent.

Две новые вещи здесь происходит: Мы создали точки взаимодействия, может служить источник или получатель сообщения (в этом случае он будет оба);и два, мы использовали оператор перенаправления для создания конвейера сообщений от точки взаимодействия функции ProcessArgument. При этом все сообщение, отправляемое «аргументы»точки взаимодействия будет перенаправляться ProcessArgument, а обработка. Оттуда, все, что осталось — итерацию аргументов командной строки и отправить каждый из них как сообщение (через оператор отправки <--операция внутри цикла) взаимодействия аргументы начинается точки и работы.

(Axum формально определяет это как сеть потока данных и есть много его способов Кроме создания простой конвейера 1-1, но это выходит за рамки этого введения. Руководство программиста имеет более подробные сведения для тех, кто заинтересован.)

На рис. 4 изменения версии ProcessAgent

using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;
namespace Process
{
public domain Program
{
agent ProcessAgent : channel Microsoft.Axum.Application
{
public ProcessAgent()
{
String [] args = receive(PrimaryChannel::CommandLine);
// Second variation
//
var arguments = new OrderedInteractionPoint<String>();
arguments ==> ProcessArgument;
for (var i = 0; i < args.Length; i++)
arguments <-- args[i];
PrimaryChannel::ExitCode <-- 0;
}
function void ProcessArgument(String s)
{
Console.WriteLine(“Got argument {0}”, s);
}
}
}
}

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

Более того концепция конвейеризация сообщения из одной точки взаимодействия — мощная концепция, Axum наследует из функциональных языках вроде F #. Рис. 5 показывает, как просто добавить дополнительная обработка в конвейер.

Обратите внимание, что снова функции UpperCaseIt не изменяя внутреннее состояние ProcessAgent но работает только на объекте, передаются. Кроме того конвейера изменяется для включения перед функцией ProcessArgument UpperCaseIt и происходит самое интуитивно--результаты UpperCaseIt передаются в функцию ProcessArgument.

В качестве мысленным упражнение рассмотрим сколько строк кода на C# для этого требуется бы работе в виду, что все это также выполняется через несколько потоков не только один поток выполнения. Теперь представьте, отладка кода убедитесь, что он выполняется правильно. (На самом деле, imagining его не обязательно--средство ILDasm или Reflector для проверки созданного IL. Это определенно не тривиальная.)

Кстати, у МЕНЯ есть мелких confession вносить--как написано, Мои примеры не выполнялась правильно. При выполнении предыдущего кода приложение возвращает без отображения ничего. Это не ошибка в Axum бит;Это как предполагаемого поведения и выделяет как программирование параллельной мышления требует мысленным shift.

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

Чтобы устранить эту проблему, ProcessAgent необходимо заблокирован до завершения операции; конвейераон должен для хранения потока активности с примерно Console.ReadLine(). (Это оказывается быть непросто на практике — просмотреть блог группы Axum для сведений о.) Или необходимо изменить способ работает ProcessAgent, а именно этот последний курс, я собираюсь предпринять, главным образом для демонстрации несколько больше возможностей Axum.

Вместо выполнения работы внутри себя ProcessAgent будет отложить работу нового агента. Но теперь, просто чтобы сделать вещи чуть интереснее, этот новый агент будет также известно ли аргумент должен быть прописные или строчные. Для этого нового агента необходимо будет определить более сложное сообщение, тот, который принимает не только строку для работы, но также логическое значение (ИСТИНА для прописные). Чтобы сделать это, Axum требуется, чтобы мы определено схему.

На рис. 5 конвейеризация сообщения

using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;
namespace Process
{
public domain Program
{
agent ProcessAgent : channel Microsoft.Axum.Application
{
public ProcessAgent()
{
String [] args = receive(PrimaryChannel::CommandLine);
// Third variation
//
var arguments = new OrderedInteractionPoint<String>();
arguments ==> UpperCaseIt ==> ProcessArgument;
for (var i = 0; i < args.Length; i++)
arguments <-- args[i];
PrimaryChannel::ExitCode <-- 0;
}
function String UpperCaseIt(String it)
{
return it.ToUpper();
}
function void ProcessArgument(String s)
{
Console.WriteLine("Got argument {0}", s);
}
}
}
}

Обработать Мой аргумент

Неявно до этой точки одной из целей Axum было изолировать различные выполнение сущности (агенты) от друга и он выполняется так сделать копии сообщений и их агент передачи, а не непосредственно передача объектов. Нет общего состояния--даже через параметры--означает отсутствие случайного вероятность конфликта потоков.

Хотя это хорошо работает для типов, определенных в библиотеке базовых классов .NET, может легко быть нарушается если программистам .NET не правильную вещь определяемые пользователем типы. Для борьбы это Axum требуется новый тип сообщений определяться как тип схемы--по существу объекта без методов и обязательные и необязательные поля, используя ключевое слово схемы:

schema Argument
{
required String arg;
optional bool upper;
}

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

channel Operator
{
input Argument Arg : String; // Argument in, String out
}

Определен этот канал, он становится относительно тривиальных записать агент, который реализует канал, как показано на рис. 6. Заметьте, что этот агент технически никогда не завершается его конструктор--просто вращается в цикле, вызов получения Arg порт, блокирование до аргумента, передается экземпляр а отправка результатом ToUpper или ToLower обратно же порту (в зависимости значения верхней, разумеется).

На рис. 6 агента реализация канала

agent OperatingAgent : channel Operator
{
public OperatingAgent()
{
while (true)
{
var result = receive(PrimaryChannel::Arg);
if (result.RequestValue.upper)
result <-- result.RequestValue.arg.ToUpper();
else
result <-- result.RequestValue.arg.ToLower();
}
}
}

От вызывающих объектовперспективы (пользователей), с помощью OperatingAgent не отличается от ProcessAgent самого себя: Мы создать экземпляр класса с помощью встроенных методов CreateInNewDomain и запустите учет экземпляры аргументов Arg порта. При этом, однако объект возвращается, в конечном итоге будет yield ответа от агента, который является единственным способом сбора результатов (через другую операцию receive()), как показано на рис. 7.

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

Поэтому Little еще так районах

Axum ясно представляет другим способом думать о программировании и несмотря на его stark отличия от C#, реализует значительное число функций, найденные в наиболее универсальных языков программирования. Его основное назначение, однако центров вокруг параллелизма и поток понятного кода и таким образом, лучше всего работает с проблем, которые требуют (или воспользоваться преимуществами) параллелизма.

К счастью построение Axum группы не пытаться reinvent языка C#. Поскольку Axum компилируется в сборки .NET, как другими языками .NET, это относительно тривиальных построение доступно одновременных части приложения в Axum (виде проекта библиотеки классов, вместо консольного приложения) и затем вызвать в него из C# или Visual Basic. Распределение Axum поставляется образец, не (О философы примере, иллюстрирующих проблемы классический параллелизма в приложении WinForms), и качество времени с Reflector через библиотеки Axum компиляции будет большую Показать о, объем взаимодействия. С помощью Axum для построения библиотеки библиотеки, вызываемой из другого языка (C# или Visual Basic) могут перейти долгий путь сторону внесения использовать большой параллелизма значительно более доступными на другие технологии .NET, такие как Web или настольных приложений.

На рис. 7 с помощью метода CreateInNewDomain

 

agent ProcessAgent : channel Microsoft.Axum.Application
{
public ProcessAgent()
{
String [] args = receive(PrimaryChannel::CommandLine);
var opAgent = OperatingAgent.CreateInNewDomain();
var correlators = new IInteractionSource<String>[args.Length];
for (int i=0; i<args.Length; i++)
correlators[i] = opAgent::Arg <-- new Argument {
arg = args[i],
upper = ((System.DateTime.Now.Millisecond % 2) == 0) };
for (int i=0; i<correlators.Length; i++)
Console.WriteLine("Got {0} back for {1}",
receive(correlators[i]), args[i]);
PrimaryChannel::ExitCode <-- 0;
}
}

На самом деле Axum использует экспериментальной компилятор C#, предоставляющий некоторые интересные и различные возможности, надмножество C# 3.0 (3.0 + асинхронных методов), ни один из которых подразумевается для C# 4.0, способом. Однако, что это разрешить, является способность кода C# и Axum смесь и совпадения в одном проекте нечто уникальных Axum до сих. Увидеть Руководство программиста Axum details.Axum имеет дополнительные возможности, не описанных здесь, рассматриваются в некоторые подробности в руководстве программиста Axum, включая закрыть связь с WCF для упрощения записи службы максимальный масштаб, но это введение должно быть достаточно начать построение приложения, библиотеки или служб Axum. Помните, что это проект исследования и пользователи могут предложить обратной связи через на форумах Axum на DevLabs веб-узле.

Что делать, если сбой Axum превратить в доставке продукта или читателей хотите использовать раньше? Новичкам следует иметь в виду, успех или неудача Axum зависит значительно частично реакции пользователя и будет жить или смерти отзывы качества--отправить команде Axum свои мысли и agitate его выпуска открытого манере! Но даже если Axum не выпускник, помните, принципы Axum не уникальный. В учебных заведений phraseology Axum включает Актеры модели параллелизма и несколько других моделей Актеры доступны для разработчиков .NET, желающий примерно для производства сегодня. Открытие исходного проекта "Retlang"включает ряд понятий, как языка F # (рассмотрим тип F # MailboxProcessor) или Microsoft блокировки и управления среды выполнения (CCR), которые являются состояния около отгрузки, если не уже существует.

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

И помните, что Quot linguas calles, tot homines vales.

Тэд Ньюард (Ted Neward) является участником Ньюард и Associates, через который он говорит, записывает и coaches о создании надежных корпоративных систем. Он записан множества книг, изучении и говорят на конференциях по всему миру, является INETA динамика и получил награду MVP в трех различных областях специализации. Достичь ему на ted@tedneward.com или через его блог по blogs.tedneward.com.