Конвейер (Pipeline) — IV

Ближе к жизни

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

Итак, обычно на каждую фазу бывает по сервису. В таком случае, все же будет разумно, чтобы сервис имел поток публикуемых результатов.

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

Подробнее

Конвейер (Pipeline) — III

Конвейер для больших массивов

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

До этого я специально взял количество данных в наборе равное четырем. Так как это еще разумное количество потоков для многопроцессорных машин. Для экспериментов приближенным к реальности можно взять количество элементов равным 60.

По сути код останется тем же, только надо увеличить количество элементов.

Линейную реализацию с перебором всех значений не будем рассматривать уже как совсем не интересную.

При работе с Task, замеры времени показывают среднее значение обработки в 51 секунду. Это означает, что все 60 потоков не создаются одновременно, а выстаиваются в какую-то очередь и все это безобразие занимает 51 секунду (разброс от 50 до 53 секунд), если использовать такой код:

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

Подробнее

Конвейер (Pipeline) — II

Конвейер для небольших массивов

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

Обработка одного значения совсем не интересно, гораздо интереснее посмотреть временные затраты при небольших массивах. Для начала пусть будет 4 значения в массиве.

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

Ничего сложного, но зато можно отследить порядок выполнения фаз. При прохождении через сервис, мы должны получить значение с постфиксом «smf».

Подробнее

Конвейер (Pipeline) — I

Сложность 200-400

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

Преамбула

Задача в общем смысле стояла примерно так:

  • С некоторой периодичностью приходят файлы данных в xml;
  • Файлы надо распарсить;
  • Проверить данные, контрольные суммы, верность указания справочников;
  • Отправить пользователю на проверку суммарные данные;
  • Сохранить данные в базу.

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

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

Подробнее

Async\Await методы и PostSharp

Сложность 300-400

Описание проблемы

Уже много чего написал насчет PostSharp, конкретных решений, кастом компонентов, общие принципы работы. Однако с выходом .Net 4.5 появилась новая фича со специальными словами async\await которые позволяют более просто и компактно описывать асинхронное поведение методов. Новый функционал хорош, но добавляет головной боли при использовании PostSharp, с методами помеченными async, использование классических аспектов не пройдет. Методы с маркером async разворачиваются в машину состояний, что не очень хорошо с точки зрения применения аспектов. Т.е. возьмем стандартную реализацию аспекта трассировщика с помощью  PostSharp:

И применим его к тестовому примеру с вызовом синхронных и асинхронных методов с исключениями и без:

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

Подробнее

Async/Await для .Net 4.0 Video

Сложность 200-400

Буквально на днях в блоге разработчиков Base Class Library промелькнуло известие о том, что теперь можно использовать async/await и для кода написанного на .Net Framework 4. А это значит можно использовать удобный подход для асинхронной работы, даже если пользователи вашей программы до сих пор сидят на «старой, доброй XP» по тем или иным причинам. Естественно такая новость не могла пройти мимо меня, чтобы я не попробовал как оно на самом деле в использовании. Забегая вперед, и что вполне ожидаемо, работает все точно так же как и в 4.5 за исключением некоторых нюансов в процессе разработки.

Процесс работы с новыми возможностями показан на видео подкатом.

 

Hard’n’Heavy!

Async/Await для .Net 4.0

Сложность 200-400

Буквально на днях в блоге разработчиков Base Class Library промелькнуло известие о том, что теперь можно использовать async/await и для кода написанного на .Net Framework 4. А это значит можно использовать удобный подход для асинхронной работы, даже если пользователи вашей программы до сих пор сидят на «старой, доброй XP» по тем или иным причинам. Естественно такая новость не могла пройти мимо меня, чтобы я не попробовал как оно на самом деле в использовании. Забегая вперед, и что вполне ожидаемо, работает все точно так же как и в 4.5 за исключением некоторых нюансов в процессе разработки. Но обо всем по порядку.

Команда разработчиков анонсировала пакет дополнений, который позволяет использовать await в Visual Studio 2012 (в предыдущих версиях работать не будет). Выпущенный пакет может быть применен к следующим платформам (указанной версии или выше):

  • .NET Framework 4.0 (with KB2468871)
  • Silverlight 4
  • Windows Phone 7.5
  • И портируемые библиотеки опирающиеся на указанные платформы.

Т.е. это не встроенная фича .net 4.5?

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

Принимая вышесказанное во внимание, разработчики ожидают возможность использования await как только они переходят на новую студию – независимо от платформы языка. Если вы задумывались о том, как реализовано большинство фич языка, то вы можете догадаться, что многие вещи не просто данность и особенность языка. Множество конструкций языка опираются на вполне конкретные API, к примеру, методы расширения опираются на ExtensionAttribute, а foreach зависит от интерфейса IEnumerable. В случае с await потребуется давно любимый класс Task и некоторая хитрая обвязка, которая делает возможным использование await.

Подробнее

PostSharp Thread\Dispatcher Toolkit

Сложность 100

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

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

О том как решаются эти проблемы в «традиционном» стиле, я рассказывал в статье про эволюцию сервисных методов, там же описана библиотека MakeMeAsync, которой я с удовольствием и активно пользуюсь на данный момент. Не буду повторятся какие альтернативы существуют. Сейчас уже официально выпущен .Net Framework 4.5 c поддержкой конструкции async\await, так что я надеюсь что использование монструозных конструкций для выполнения кода асинхронно будет сходить на нет.

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

Подробнее

Make me async

Сложность 200

Почти месяц назад я написал статью «Эволюция сервисных методов». В ней я пришел к реализации библиотеки MakeMeAsync, которая позволяет декорировать вызовы методов, делая их асинхронными. При этом код остаётся максимально читабельным и чистым, на мой взгляд.

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

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

Итак, я думаю, что для начала стоит обновить информацию о том, как используется библиотека MakeMeAsync.

Подробнее

Обработка исключений при работе с классом Task

Сложность по шкале Microsoft 200

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

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

Все последующие примеры не открывают Америки и все прекрасно описано в книги  J.Albahari “C# in the Nutshell 4.0”, но пока не увидишь, как не надо делать, сложно бывает запомнить как надо.

Подробнее