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

Ближе к жизни

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

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

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

Подробнее

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

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

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

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

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

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

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

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

Подробнее

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

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

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

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

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

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

Подробнее

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

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

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

Преамбула

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

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

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

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

Подробнее

Сообщения с таймером

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

Задумка

Я думаю, что если подумать, то все вспомнят о статусной строке в приложении, где часто пишется состояние программы, уведомления о завершении каких-либо фоновых задач, другая интересная информация о работе программы. Еще можно вспомнить о программах, которые показывают информационное сообщение пользователю в каком-либо специальном месте на интерфейсе, а через какое-то время (секунд 5) надпись исчезает. Учитывая последние тенденции к тому, чтобы избавлять пользователя от popup-окон, в которых написано что-то в духе: Данная операция не может быть совершена, так как она в процессе выполнения, — и на всплывшем окне только одна кнопка OK. Раздражает такое поведение неимоверно, так как приводит к лишним действиям! В общем, сегодня я покажу, как можно реализовать набор классов для реализации такого поведения и использовать его в дальнейшем без существенных модификаций.

Неискушенный читатель наверно может воскликнуть: «Что за бредятина, какие еще  наборы классов для того, чтобы сделать два set’a строки? Надо показать сообщение, так присвоил переменной сообщения нужный текст, когда не надо – присвоил пустую строку. Any problem?»

Если кратко, то проблем много! Сейчас попробую перечислить их, как они придут в голову:

  • Много инфраструктурного кода получится, ведь надо будет вводить таймеры, ответы и наверняка что-то еще. И это каждый раз при попытке сменить текст.
  • Надо запоминать предыдущий текст в сообщении, если он был.
  • Легко запутаться что, где и зачем реализовано. Скорее всего, будет много копи-пасты, а следовательно больше мест для ошибок.
  • Некрасиво!

Лично для меня хватило только первого пункта из-за моей профессиональной лени.

Подробнее

Иерархичные структуры данных и промежуточные расчеты

Традиционной, в плане изучения программирования в школах, университетах, курсах повышения квалификации и так далее – является архитектура, в которой мы явно управляем ходом выполнения программы. Это начинается с фактически процедурного турбо паскаля и идеологически продолжается в «рабочих» для бизнес-программирования языках (С# и Java). Каждое действие программы задается явно, т.е. если надо что-то пересчитать после добавления нового элемента в коллекцию, то так и пишут: сервис Х пересчитай мне коллекцию с помощью метода Z. Это – push модель, мы толкаем/принуждаем систему сделать определенные действия.

Более интересной является pull модель, когда объекты сами говорят о том, что с ними следует сделать. При той же ситуации, что описана выше, надо только добавить объект в коллекцию, а дальше уже коллекция сама может сказать сервису Х пересчитать себя с помощью метода Z. Система реагирует на события внутри себя.

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

Подробнее