Комментарии 75
> Если статья будет интересна сообществу, эти моменты я раскрою подробнее.
Да, раскройте, пожалуйста! Очень интересно.

За статью спасибо, но хотелось бы побольше кода. Элементарный реальный пример помог бы быстрее въехать в Ваш подход.
Что касается кода — то это, вообще говоря, практически любая многопоточная программа.
Например, GUI в параллели с которым идёт обработка.

Скажем, в моей области (управление технологическими процессами) с применением GUI. GUI — как правило, главный поток, кроме него есть поток, который «принимает решения» по генеральному управлению линией, а также потоки журнала, потоки обмена с контроллерами узлов линии, потоки обмена для синхронизации по сети. Всего порядка 10-12 штук, которые активно взаимодействуют друг с другом посредством асинхронных сообщений. Например, поток журнала, с которым взаимодействуют все. Или поток сетевой синхронизации, который делает запросы в журнал не только для чтения/записи, но и для запросом на кэширование определённых записей в целях ускорения инкрементальной синхронизации журналов по сети.
Или «принимающий решения» поток активно взаимодействует с GUI, но при этом не может позволить в нём постоянные локи — очень нехорошо отражается на взаимодействии с пользователем.
Страшно представить, сколько бы понадобилось отлаживать без асинхронных сообщений.

Или вот пример попроще. Веб-сервер, который на каждый тип задания или пользователя рождает Worker. А сам Worker — конвейерный поток, который отвечает на запросы и выполняет полезную работу. Без необходимости в излишней синхронизации.
Я имел в виду — реальный пример кода. Простенькая программа, пусть даже бессмысленная, но иллюстрирующая принцип конвейерных потоков. Зачем нужна многопоточность я знаю, и даже использую её. =)
Совсем простенький недопример я привёл в статье.
Пожалуйста уточните, что ещё нужно, я обязательно добавлю.
Это именно «недопример», а хотелось бы увидеть и организацию самой очереди, и спящие до поры до времени потоки. То есть, реальный код, который можно собрать и запустить самому. И поковырять.
Вынесите пожалуйста вот эти две ссылки в текст статьи. Предвижу много таких просьб.
На мой взгляд то, что описал автор похоже на организацию пула потоков в mongodb. Посмотреть можно тут и тут.
Сам недавно реализовал нечто подобное на C#. Тоже вычитав на Хабре про подход Erlang. Отлично работает. Передачу данных между потоками асинхронным вызовом (сообщением) полностью поддерживаю. ИМХО, синхронные вызовы лучше использовать только внути одного потока, между потоками — только ассинхронные.
Когда прочитао это:
> «Если своими словами и вкратце, речь идёт о том, что каждая подзадача работает со своим «адресным пространством» (вернее, набором данных), то есть изолирована от других. И единственный способ взаимодействия подзадач — обмен асинхронными сообщениями.»

То понял что это изобретение форкания процесса, и межпроцессного взаимодействия. А смысла? Ну чуть более обезжиренным будет, так как не системным вызовом делает и не ведется ядром. А в целом 1:1 POSIX процессы.
Или я не понял чего-то…
Сорри за опечатки — быстрое печатание на планшете еще не освоил :)
То есть вопрос даже не «в чем смысл», а в чем суть интересного метода? В том, что это создание собственных процессов, только отвязанных от ядра? Они именно так и работают.
Суть метода — в другой модели взаимодействия потоков (чётко оговорены ограничения, которые я накладываю на код С++). Я утверждаю, что применение данной модели позволяет создавать более стабильные и масштабируемые приложения без потери эффективности (практически или полностью) в сравнении с обычными объектами синхронизации. Как заметили здесь в комментариях, данный подход становится всё более актуальным с переходом на многоядерные процессоры.

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

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

По крайней мере, я поставил на повестку дня многопоточные программы без мьютексов и семафоров. Со всеми их плюсами и минусами. Это немного другой подход к многопоточности, который, в идеале, я и стремлюсь обсудить. Надеюсь сделать это в следующей статье, которая будет посвящена исключительно этому, где не придётся размениваться на описание что такое конвейерные потоки.
Ну и почему же обмен сообщениями безопасней мьютексов? (С эрлангом знаком.)

Что делать с ростом latency при переходе на сообщения?
Почему отсутствие объектов синхронизации, которые являются постоянным источником багов, лучше их наличия — надеюсь, объяснять излишне.

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

По поводу задержек, вы даете очень странный ответ. Приведу пример для лучшего понимания. Допустим есть некоторый кеш, и рабочие потоки постоянно туда заглядывают. Если делать кеш отдельной задачей с общением через обмен сообщениями, каждое обращение к кешу замедлиться за счет задержки на обмен сообщениями. Затраты на копирование сообщения исчезающе малы — тут я с вами полностью согласен. Проблема в том, что задача, которая обслуживает обращения к кешу, может крутиться на другом ядре, и чтобы ее разбудить, потребуются IPI. А если даже задача крутится на текущим ядре — еще не известно, когда ОС поставит ее на выполнение.
Если у Вас нет проблем с объектами синхронизации, то я вполне допускаю, что Вам моя статья просто неактуальна. А соответственно и спор о её преимуществах изначально бесплоден.

Что касается таких вещей как кэш, то, в общем случае, это одна из тех задач, где классическая синхронизация подходит куда лучше очередей.
Ну извините, что прицепился)
Я согласен, что есть масса задач, где системы, основанные на сообщениях очень хороши.
Но говорить «мьютексы–плохо, вот вам серебрянная пуля» — это все же перебор, не находите?

Чем так хорош Erlang? Он заставляет писать в определенном стиле. Это ни в коей мере не панацея — если постараться, дедлок можно получить и на сообщениях. Но возможности программисту накосячить (в части многопоточности) куда меньше, чем в Cи/C++. В Си тоже можно писать надежные многопоточные программы — если писать в определенном стиле)

А статья мне ваша понравилась, кстати.
Про «серебряную пулю» — это Вы придумали, уважаемый mejedi. Я же писал совсем другое:
Ну и наконец, надо понимать, что любой подход не является панацеей на все случаи жизни. Например, основной поток высокопроизводительного веб-сервера — это задача из другой области.
В начале статьи тон слегка другой. Впрочем, готов признать свою невнимательность и давайте на этом закончим.
«The source code for the library that provides the implementation of GCD's services, libdispatch, was released by Apple under the Apache License on September 10, 2009[3] It has been ported[4] to the FreeBSD operating system, starting with FreeBSD 8.1.[5] MidnightBSD 0.3-CURRENT includes «libdispatch» without blocks support.[6] Linux and Solaris support are provided within the upstream trunk.[7][8] In order to develop support for Windows, currently two forks exist at opensource.mlba-team.de and Github.[9][10]»

via wikipedia
Не совсем понял назначение вашего коментария. Просто чтоб людям не лезть в википедию?
Я не согласен с вашим утверждением («лучше чтобы сие предоставляла ОС»), и привожу в качестве аргумента тот факт, что пресловутая GCD способна работать на Linux, BSD и Windows.
Хм либо запрограмился либо не понимаю как «лучше чтобы сие предоставляла ОС» конфликтует с «реализовано на разных платформах».
Смысл того что я сказал — желательно чтобы реализация thread-safe очередей и прочего подобного было на уровне ОС, которая точно знает как это сделать наиболее эффективным способом…
Насколько мне известно, поправьте меня если я не прав, GCD реализована целиком в юзерспейсе, и в ядро для ее эффективной работы ничего не добавляли.

Контр-пример: в Linux mutex и condition variable реализованы через ядерный примитив futex. Futex был специально спроектирован так, чтобы сделать реализацию condition variable эффективной. Фишка тут вот в чем — condition variable всегда используется совместно с мьютексом. По спецификации pthread_cond_broadcast() будит все ожидающие потоки, и они тут же начинают гонку за мьютексом. Очевидно, выиграет только один а все остальные снова заблокируются. Это слегка неэффективно. Чтобы избежать ненужной гонки, в futex есть специальная операция: присоединить waitlist одного фьютекса (внутри condition variable) в конец waitlist другого фьютекса (внутри мьютекса).

Конечно, то что «фичу X предоставляет ОС», вовсе не означает, что фича X обязана быть реализована именно в ядре — тут уже я «запрограммировался» :)
>> Я не согласен с вашим утверждением («лучше чтобы сие предоставляла ОС»)
Когда job manager реализован в программе и система об этом ничего не знает, это может привести к печальным результатам. ОС переключает задачи абы как, а не по границам job-ов. Из-за этого, если у вас есть зависимости между job-ами (скажем одна группа подготавливает данные, а другая их использует) то неконтролируемая задержка вызванная прерыванием выполнения одного из job-ов может сильно испортить жизнь остальным.
Например вот тут есть реальные цифры
farrarfocus.blogspot.com/2010/01/pc-cpu-task-parallelism-limits.html

Можете привести пример хоть одной ОС, в которой это реализовано? Сдается мне, что задержка в таком случае — неизбежная плата за абстракцию.

C priority inversion как-то борятся, и на том спасибо.
Так делают на консолях.
Возможно GCD в OS X работает так же. Не проверял.
GCD мало того, что не «предоставляется самой ОС» (это библиотека), так еще и не умеет кучу вещей (например нельзя строить dataflow сети для процессинга сообщений) и зависит от собственного синтаксиса для лямбд (блоки), который опять таки более ограниченный, чем родной плюсовый (весьма неочевидный контроль захвата по ссылке/значению и при этом не такой гибкий, чем у плюсовых лямбд).

Если хочется многопоточного message passing-а, то лучше пользоваться или Intel TBB или (если речь только о винде) — родной Visual Studio-йной Concurrency Runtime.

Преимущество перед самописными костылями хотя бы в том, что
1. Не нужно поддерживать самому
2. Реализация гораздо эффективнее (lock free work stealing очереди, агрессивный инлайнинг и пр)
Поскольку блоки — расширение языка Си, с захватом окружения блоками все просто и очевидно — копируются POD типы, а других просто быть не может.
Поскольку блоки — расширение языка Си

Вообще, блоки — это расширение языка Obj-C. И пришли они оттуда же откуда пришли все остальные «расширения» этого языка (и даже называются так же как в оригинале).

захватом окружения блоками все просто и очевидно — копируются POD типы

Если бы я хотел «расширений C», я бы взял OpenMP. А в случае C++ надеяться на то, что все переменные будут POD — уже нельзя.

а других просто быть не может

Все не так «просто и очевидно». Ctrl+F "__block" в официальном описании

Вообще весь GCD выглядит как то коряво, ограниченно и нормально вписывается только в Obj-C (который лично мне не нравится именно своей эклектичностью).
А еще из блоков нельзя «выпускать» иксепшены. Но для Си и на эппловской платформе — вполне съедобно.
К счастью, перед тем как мне предоставилась возможность изобрести подобный велосипед, я узнал о Boost.Asio и его io_service

:)
В этом наверное тоже есть смысл, но на мой взгляд это слишком «тяжёлое» решение. Потому что оно тянет за собой сокеты, таймеры и прочее. Допускаю что в ряде случаев оно вполне оправдано.
Надеюсь Вы извините меня за мой велосипед и как попытку сделать достаточно лёгкое и универсальное решение с минимумом зависимостей.
Вообще-то io_service — это универсальная библиотека целью которой является именно передача сообщений.
Сокеты asio ее используют, а не наоборот.

Велосипеды полезны при изучении разных концепций, а в работе нужно использовать стандартные решения (если у вас конечно нет задачи обфускации исходников).

Аргумент про тяжесть мне вообще не понятен — сорри. Бывают быстрые/медленные, функционально можные/слабые библиотеки. А тяжесть — это что-то из категорий прошлого века.
Тот же подход что и классический питонский Queue, правильно я понимаю?
Безусловно, вещи близкие.
Тут вопрос немного в другой идеологии. В моём случае, очередь присутствует внутри класса-потока и явным образом нигде не фигурирует. Пользователь может лишь «запросить» у объекта-потока определённый его колбэк. Объектная мизонтропия, организованное взаимное недоверие, инкапсуляция, возведённая в жёсткое правило.
В этом смысле, Queue — питоновский аналог очереди в объекте-потоке. Кроме того, в случае С++ в очередь кладутся строго «облегчённые» колбэки с аргументами, что позволяет говорить об определённом уровне эффективности.
Повторюсь, идеологически то что Вы привели — очень близко, да.
Только начав читать статью, сразу почему то подумал про Эрланг… :)
Большое спасибо за ссылку. К сожадению, я об этой библиотеке не знал. На досуге обязательно посмотрю более пристальное. Также интересно будет сравнить быстродействие моей и их библиотек на различных платформах.
Посмотрел. К сожалению, данная библиотека не эквивалентна предложенному подходу. Дело в том, что библиотека фактически завуалировала работу с объектами синхронизацию, принципиально не разрешив их проблемы. Как можно видеть из примеров, там всё ещё возможны deadlock-и, а значит и все прочие «прелести» классической многопоточности.

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

Конечно, там есть свои проблемы, но они уже скорее «логического» порядка, не приводящие к «падению» и зависанию.
Вот вы дали ссылку на U++, по которой авторы пытаются доказать, насколько он круче Qt. Не помню, как обстояли дела с очередями в Qt 7-8 лет назад, но сегодня они является частью механизма сигналов и слотов, так что самому ничего программировать не нужно.
То есть сейчас Кьют реализует ту же задачу количеством кода, меньше чем U++? Код не приведёте?
Лаконичность это безусловно мега круто, но кроме неё есть ещё эффективность и расширяемость. Иногда ради неё приходится и чутка помудрёнее писать.
Не могу не согласиться с приведённой фразой.
Однако, не могу согласиться с ней применительно к U++. Вы можете ознакомиться с другими примерами с сайта и, возможно, придёте к выводу, что U++ не только более выразителен и лаконичен, но и вполне себе расширяем. Что касается эффективности, то и здесь есть чему на что посмотреть.
Примеры там капитанские, но не сильно то они и лаконичные, гуй на qml, к примеру, куда лаконичнее и естественнее выглядит.
И вообще складывается впечатление от туториала, что там к гую подходят примерно также, как подходили в 95 году! Все экзамплы и написанные на U++ проги поражают своим интерфейсом. На вид типичное формошлепство в дельфи стиле.
ЗЫ
И ещё нет версии под Mac Os X и под мобильные девайсы.
ЗЗЫ
А это нам демонстрирует просто чудеса кроссплатформенности:
www.ultimatepp.org/srcdoc$Sql$tutorial$en-us.html
Просто заранее прибиваемся гвоздями к определенной базе данных и всё!

connect(a, SIGNAL(foo(args)), b, SLOT(onFoo(args));



emit foo(args);

или же

qApp->postEvent(a, event);

так уж много кода для посылки сообщения в другой поток?
Тут, мне кажется, речь о лаконичности в сравнении, приведённом на сайте U++, а не в отправке сигналов.
В U++ есть хоть какой-то аналог Q_INVOKABLE и QMetaMethod::invoke?

Код примера со стороны Qt там вообще жутко устаревший, сейчас вообще всё по другому!
Если речь идёт о передаче колбэков, то, да, они есть. И, кстати, не требуют никакого пост-процессинга исходников (Кьют ещё от него не отказался?)
Вот ссылка на описание. Посмотрите, пожалуйста, это ли Вы имели в виду, или нет.
А вот и нет и без пост процессинга сырцов невозможно достичь в C++ этой функциональности.
Qt возможно в будущем откажется от moc'а, но в пользу плагина для llvm.
А вот и нет и без пост процессинга сырцов невозможно достичь в C++ этой функциональности
О чём конкретно идёт речь?
Динамический вызов метода у класса, когда совершенно не известен его интерфейс. Иногда бывает полезно, особенно если нужно вызвать метод из скрипта. В виду отсутствия в C++ настоящего RTTI приходится иногда идти на это.
Уверен, обзор и сравнение межнитевых очередей, построенных на различных механизмах синхронизации — будь-то мутексы, семафоры или CAS — нашел бы свою аудиторию.
Возможно, эту мысль уже высказывали, но советую также обратить внимание на предлагаемую Qt модель разработки многопоточных приложений, особенно модель разработки сущностей, наследуемых от QObject и их взаимодействие с потоками.

> При этом, если в том же Win API есть печеньки вроде WaitForMultipleObjects,
Когда-то тоже столкнулся с подобной проблемой. Чаще всего wait-condition + mutex/critical section + переменная, отвечающая за тип произошедшего события заменяют эту очень удобную плюшку.
Статью не осилил. Подскажите пожалуйста, что за транспортное средство изображено на картинке вначале.
«Статью не осилил»
— Что помешало, если не секрет? Старался разбавить статью картинками и не слишком усложнять (хотя было желание ввести теорию).

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

Сейчас фирмы вроде Боинг делают определённые робкие шаги в направлении экранопланов, так что заработанный «на излёте», в 70-е годы, приоритет, тает.

Данный экраноплан был назван на Западе «Каспийским монстром» за свои размеры, мощь, скорость и манёвренность. При невероятных для мореплавания скоростях, экранопланы исключительно безопасны и стабильны при передвижении.

Именно оттуда я и взял ассоциацию с названием статьи.
Если бы их массово начали делать эти бы средства тут же появились. А еще бы и появились конкуренты. Гонка вооружений, знаете ли!
Жёсткий такой оффтоп, уважаемый Алексей.)
Насчёт «тут же появились» можно поспорить — нижний порог радаров (порядка десятков метров) имеет под собой определённые основания.
И насчёт конкурентов — тоже спорно, учитывая что очень многие хотят, но не могут.
Вот скажем, например, как сделали системы с разделяющимися боеголовками, так вот уже несколько десятков лет эффективного симметричного ответа не существует.
Предлагаю замять для ясности и просто порадоваться тому, что такое уникальное и красивое «чудище морское» было сделано нашими с Вами отцами первыми в мире.
Спасибо большое за ответ! Никаких претензий к вам, просто я гуманитарий :) А, вот, самолётоподобные средства люблю!
Насколько понял вашу задумку, речь идет о еще одной реализации модели параллельного программирования на основе message passing. Потому многие и вспоминают им известные реализации из числа стандартных. Tо есть, уже существующих и во всех смыслах поддерживаемых.

Поскольку вы не изобрели модель message passing, а просто пишете еще одну реализацию «по мотивам» другой реализации одной из разновидностей этой модели (communicating sequential processes в Эрланг), постольку выглядит слегка странным рекламирование преимуществ, получаемых по сравнению со «thread-based» програмированием (которое есть разновидность модели на основе shared memory). Говорю, «выглядит странным», потому что то лишь, что ваш «message passing» выполнен посредством доступных на вашей платформе «thread based» механизмов, поводом к сравнению не является.

Если сможете сравнить то что получилось у вас с другими реализациями той же модели, вот тогда и прояснится, стоит ли игра свечь, и меньше будет упреков по поводу велосипедостроения. (Все мы, по сути, только велосипеды и делаем… Просто когда это оправдано, никто не замечает.) На всякий случай, сегодняшний стандарт де факто в части реализации «message passing» параллелизма для C/C++ и не только — это MPI. Логичнее было бы начать именно с этого и продолжить в духе патентной формулировки: а мой «каспийский монстр» отличается тем, что…
С критикой согласен. В некотором роде, комментарии немного «вправили мозги» (в этом смысле, считаю что вообще очень полезно на Хабр выкладывать свои наработки).

В защиту лишь могу сказать, что с моей точки зрения основную ценность статьи представляет собой не реализация передачи сообщений (о которой было сказано не так много), а тот факт, что я поставил на повестку дня использование иных моделей, кроме shared memory. Я постарался показать, как при этом, добавив определённые ограничения на код, избавиться от объектов синхронизации.

В этом смысле, для человека, профессионально разбирающегося в вопросе, статья интереса не представляет. Скорее, я проблематизирую «конвейерный» (communicating sequential processes) подход для тех, кто не знает что это такое либо не представляет его потенциальные плюсы. Причём пишу с позиции примерно пяти лет практического использования в production, то есть некоторого понимания плюсов и минусов. То что получилось, действительно вдохновило меня рассказать об этом людям, именно с точки зрения практики. Потому что, всё-таки, ещё одна заумная статья на тему теории массового обслуживания, применённой к работе потоков, вряд ли кому-то здесь была интересна.
Солидный опыт применения, безусловно, заслуживает уважения. Критикую только потому что насторожило вот это:
свою [реализацию очереди] «допиливал» примерно полгода

А также что, судя по всему, собираетесь сподвигнуть желающих на подобные же свершения — следующей статьей «о проектировании программ через конвейерные потоки». Конечно, если пойдет речь о применении какой-то из стандартных систем и соответствующих (этой системе!) тонкостях проектирования, тогда все вопросы снимаются.

А если просто с позиций «с мьютексами трудно отлаживать, давайте мастерить очереди», то это будет вводить в заблуждение, при всей справедливости исходной посылки. Никто не спорит, ручная синхронизация потоков через объекты в большой части случаев вообще худшее из всех возможных решений. Но из этого следует лишь, что в каждом случае нужно выбирать и модель параллелизма, и конкретный подход с инструментарием соответственно задаче. Благо, в наши дни есть из чего выбирать! Вот об этом и было бы интереснее всего почитать, пусть даже ограничиваясь подходами в пределах модели message passing. Например, с точки зрения практики использования соответствующего инструментария. И затрагивать СМО при этом ни в коей мере не обязательно.

Соглашусь по поводу ценности статьи: ставите на повестку очень актуальный подход, и чем дальше, тем он будет актуальнее (глядя на тенденции в «железе»). Но подавая его как просто альтернативу thread-based, позволяющую «избавиться от объектов синхронизации», параллельно вводите в заблуждение ту целевую аудиторию, которую сами очертили. (Уж простите за каламбур.) Потому что изначальный выбор стоит не между объектами и очередями, а между shared memory (где есть thread-based, OpenMP и еще много разного) и message passing (где есть MPI, IntelTBB, Cuncurrency Runtime и еще, кстати, ваш подход). И если уж ставить на повестку message passing как модель, то в части подходов уж во всяком случае нельзя ограничиться самодельным CallbackThread и к нему причитающимся. «Люди имеют право знать!» (с)
Алексей, не совсем понял, чем именно, с вашей точки зрения, я ввожу людей в заблуждение?
Тем, что из моей статьи не следует явного призыва пользоваться готовым решением для моделей потоков с очередями? И что некоторые сделают вывод, что её лучше сделать самому?
Явный призыв не обязателен. А хотя бы упоминание альтернатив не помешало бы. Иначе выходит, исходя из материала статьи, что недостатки thread-based подхода нужно преодолевать искусным использованием структур данных и средств синхронизации, доступных в рамках все той же shared-memory модели. И что в результате мы получим некий улучшенный подход, «потоки с очередями», как вы их называете. А это заблуждение. В результате получили кардинально иную «модель параллельного программирования, основанную на передаче сообщений» — со всеми ее подводными камнями навроде латентности, СМО и прочей фундаментальщиной.

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

К счастью, это легко поправить (например, если возьметесь за следующую статью). Если подать именно как иллюстрацию к принципам message passing модели и путям работы библиотек, которые ее реализуют. А не как изобретение, выстраданное из практики. Даже если именно так ваш код и родился (охотно верю и не имею ничего против). Но поймите и читателя, попытайтесь взглянуть глазами рядового прикладника: и так технологий, как грибов после дождя, и тут снова предлагают ознакомиться с чем-то «yet another ...» в духе «roll your own». Еще раз, спасибо за статью.
Понял Вас, Алексей. Ради таких комментариев я и выкладываю статьи на Хабр.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.