Actor-based. Success story
От: Буравчик Россия  
Дата: 27.06.12 19:28
Оценка:
У кого-нибудь есть опыт участия в достаточно больших проектах, архитекутра которых была бы основана на акторах? Т.е. система разбивалась на независимые компоненты, которые обмениваются сообщениями (и только сообщениями). Конечно, вызов методов — это тоже, в некотором роде, посылка сообщений, но интересуют системы, построенные на "настоящих" сообщениях, т.е. компонент имеет очередь сообщений и явно обрабатывает их (как в Erlang).

Какие языки/библиотеки использовались?
Удобно ли сопровождать (понимать, расширять, изменять) такие системы?
Какие есть минусы и плюсы actor-based?
Для чего actor-based стоит применять, а для чего нет?

Поделитесь опытом и мыслями.
... << RSDN@Home (RF) 1.2.0 alpha 5 rev. 17>>
Best regards, Буравчик
Re: Actor-based. Success story
От: Кодёнок  
Дата: 27.06.12 20:26
Оценка: 33 (3)
Здравствуйте, Буравчик, Вы писали:

Б>У кого-нибудь есть опыт участия в достаточно больших проектах, архитекутра которых была бы основана на акторах? Т.е. система разбивалась на независимые компоненты, которые обмениваются сообщениями (и только сообщениями). Конечно, вызов методов — это тоже, в некотором роде, посылка сообщений, но интересуют системы, построенные на "настоящих" сообщениях, т.е. компонент имеет очередь сообщений и явно обрабатывает их (как в Erlang).


Б>Какие языки/библиотеки использовались?

Б>Удобно ли сопровождать (понимать, расширять, изменять) такие системы?
Б>Какие есть минусы и плюсы actor-based?
Б>Для чего actor-based стоит применять, а для чего нет?

Я как-то написал свой actor-machine для Objective-C, используя фишку автоматического создания NSInvocation при посылке нереализованного сообщения. Сообщения настоящие, с очередью, большинство асинхронные. Про расширяемость в том проекте речи не шло (хотя с точки зрения архитектуры, перенести актер на другую машину можно легко, клиенты даже не заметят), зато из проекта полностью исчезла почти все синхронизация потоков, что на фоне предыдущих неуловимых крашей из-за неправильной многопоточности было втройне круто — параллельность есть, проблем нет! Причем нет вообще. В многопоточном программировании, если ты пускаешь новичка-программера исполнить что-нибудь в фоне и не смотришь на результат, жди краш-репортов. В actor-based в худшем случае что-то затормозит или не выполнится. (Сейчас в Mac OS X 10.6 SDK добавили блоки и dispatch_async, так что надобность во многом отпала.) Story может не очень, но success — 146%.

Здесь на форуме был (а может и до сих пор есть) @eao197, который разрабатывал аналогичный фреймворк для C++ и в чем-то серьезном его использовал. Он называл это агентно-ориентированным программированием (можешь поискать в поиске), но это в принципе один хрен то же самое, может разве что без акцента на параллельность.

Главный (для меня) минус в том, что без поддержки и языка и рантайма, оно никогда не будет красивым и удобным, всегда надо что-то руками писать или с чем-то мириться (в случае с моей Obj-C машиной это -10% производительности из-за создания лишнего объекта и полдесятка лишних вызовов). Но это для меня.

По-настоящему серъезные минусы это
— в actor-based архитектуре очень легко получить дедлок;
— баг, который в простой однопоточной реализации проявляется как stack overflow и немедленный краш потока, при разбитии на акторы мутирует в отжирание 100% памяти на эту самую очередь сообщений и в результате краш всего приложения (а также других приложений в системе т.к. к out of memory как оказывается никто из них никогда реально не готов);
— отлаживать их коммуникацию мне до сих пор непонятно как, кроме как писать логи.

Но по сравнению с трудноуловимыми race condition это пустяки, если честно.

Я лично считаю что многопоточность и примитивы синхронизации — это недоразумение и каменный век, типо макроассемблера, который лишь в единичных узких местах оправдан, а будущее за message-passing concurrency. Task-based concurrency библиотеки (что то же самое) в c# и java давно уже отлично себя показывают, при правильном применении подходят почти везде. Многие новые языки (напр. Go, Rust) делают ставку строго на message-passing, вообще не допуская других типов параллельности в принципе. Есть еще STM, который так и не выстрелил нигде, и мне всегда казался костылем в попытке поправить многопоточность, но кто его знает (вроде хаскеллевцы по неуловимой для меня причине надеятся именно на STM, почему?).

Применять стоит везде, где неудобства (см. главный минус) и возможные накладные расходы не представляют проблемы.
Re: Actor-based. Success story
От: vdimas Россия  
Дата: 27.06.12 22:07
Оценка: :))
Здравствуйте, Буравчик, Вы писали:

Б>У кого-нибудь есть опыт участия в достаточно больших проектах, архитекутра которых была бы основана на акторах? Т.е. система разбивалась на независимые компоненты, которые обмениваются сообщениями (и только сообщениями). Конечно, вызов методов — это тоже, в некотором роде, посылка сообщений, но интересуют системы, построенные на "настоящих" сообщениях, т.е. компонент имеет очередь сообщений и явно обрабатывает их (как в Erlang).


Windows? ))

Когда конкретный компонент имеет очередь сообщений — это неинтересно. Бери дотнетный ремоутинг, получишь тоже самое. Интереснее, когда очередь сообщений верхнего уровня в системе общая, а каждое сообщение перед обработкой ресолвится, то бишь ищется подходящий обработчик (или подсистема более низкого уровня иерархии, которая далее сама разбирается с сообщением). Это что-то типа дополнительного уровня полиморфизма и разбиение всей системы на действительно независимые модули.

Сами сообщение примерно такие: { Target; Code; Map[tag, value] fields; }

Есть предопределенный набор кодов сообщений и тагов, а остальные регистрируются прикладными модулями так же как регистрируются динамические коды сообщений Windows. Target может иметь сложную структуру, либо просто текст с некими name-convention.


Б>Какие языки/библиотеки использовались?


C#, библиотека самописная миниатюрная. Все уже изобретено до нас, см windows. Единственно что — библиотека может использоваться гибко/произвольно, т.е. некий модуль внутри себя может иметь точно такую же очередь сообщений и перенаправлять сообщения в глобальную очередь лишь при необходимости.


Б>Удобно ли сопровождать (понимать, расширять, изменять) такие системы?


Именно расширять удобно. Произвольной функциональностью. Для этого и писалось.


Б>Какие есть минусы и плюсы actor-based?

Б>Для чего actor-based стоит применять, а для чего нет?

Стоит применять там, где тебе нужная некая "платформа" самого общего плана, определяющего основные понятия, а конечная функциональность зависит от сочетания "приложений" — плагинов и их настроек. Например, на подобном ядре VoIP можно построить как простой прокси с преобразованием форматов, так систему конференций или цифровую АТС с шифрованием.

Еще подход полезен там, где нужна динамичность, чтобы "приложения" можно было загружать и останавливать.
Re[2]: Actor-based. Success story
От: sergeyt4  
Дата: 27.06.12 22:48
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, Буравчик, Вы писали:


V>Сами сообщение примерно такие: { Target; Code; Map[tag, value] fields; }


Меня больше всего смущает сложность отладки таких приложений.

Вот, к примеру, поставили вы breakpoint в обработчике сообщений. Как узнать, откуда и почему мы сюда попали? В обычном приложении мы видим в отладчике весь stack и можем переключиться на любой frame, увидеть исходный код того места, где был вызов и значения переменных в том месте и понять почему и как мы оказались в данном месте. Даже если была цепочка вызовов.

Еще: как ни крути, в конце концов приходишь к тому, что алгоритм работы модулей программы построен на схеме "запрос-ответ". Синхронно ли, асинхронно ли, но так. А схемы вроде broadcast и notification handlers используются только в event-ах, которые не возвращают результат. Т.е. в 99% случаев есть некий вызов с параметрами и ожидается результат именно этого вызова (а не предыдущего). В actor-based приложениях это как-то реализовано на уровне языка/рантайма или приходится самому руками реализовывать (например, в каждом сообщении передавать уникальный id запроса и "обратный адрес", на который надо выслать ответ) ?
Re: Actor-based. Success story
От: WolfHound  
Дата: 28.06.12 07:06
Оценка: 2 (1) +1
Здравствуйте, Буравчик, Вы писали:

Акторы нарушают SRP.
Ибо очередь сообщений и поток исполнения не связанные между собой сущности. А акторы прибивают гвоздями одно к другому.
Это приводит к реальным проблемам, когда нужно организовать общение с несколькими акторами.
Ибо вместо того чтобы создать по каналу на соседа и точно знать какой ответ пришёл от какого соседа. Придется в каждом ответе протаскивать отправителя и руками разбираться от кого пришёл ответ.
Также начинаются проблемы, если мы хотим дождаться ответа от одного актора, а ответ от другого приходит раньше. Лечится это при помощи selective receive но он сам по себе создает кучу проблем. В частности выборка сообщения из очереди O(N) от размера очереди. Те полный разбор очереди O(N^2).
Данная проблема приводит к тому, что при кратковременном наплыве сообщений мы можем оказаться в ситуации, когда программа только и делает что копается в очереди. При этом очередь будет продолжать расти.

Короче модель каналов из сингулярити наше все.
А если еще и язык поддерживает проверку протоколов, то все совсем хорошо получается.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 08:47
Оценка: 9 (1)
Здравствуйте, sergeyt4, Вы писали:

V>>Сами сообщение примерно такие: { Target; Code; Map[tag, value] fields; }


S>Меня больше всего смущает сложность отладки таких приложений.


Наоборот просто, ведь каждый модуль/плагин можно отлаживать независимо по очень простому интерфейсу. Скажем так, уровень атоматизации юнит тестирования модулей такой системы не сравним с обычным юнит-тестированием даже на моках. Из-за однородности интерфейса... Ты только начни писать туда хелперы для тестирования и уже не сможешь остановиться. )) Полностью декларативно и минимально выходит.

И самое главное, кол-во вызовов через этот механизм, в сравненеии с общим кол-вом вызовов, не так жу велико. Это же специальный механизм спайки модулей. Альтернатива DI-контейнерам на жестких интерфейсах с кучей плюшек сверху.

Тпичный сценарий: листенер некоего протокола получает входное сообщение, достает из него требуемые поля, формируя сообщение по соглашениям системы, и пуляет его в глобальную очередь. А что происходит дальше — зависит от других приложений и их настроек... просто как-то участвовал в разработке VoIP на жестких типизированных внутренних интерфейсах — брр... Это для отладки надо писать нехилые заглушки на каждый чих. А в описанной системе отладочные модули миниатюрные и автоматизированные в разработке.

S>Вот, к примеру, поставили вы breakpoint в обработчике сообщений. Как узнать, откуда и почему мы сюда попали? В обычном приложении мы видим в отладчике весь stack и можем переключиться на любой frame, увидеть исходный код того места, где был вызов и значения переменных в том месте и понять почему и как мы оказались в данном месте. Даже если была цепочка вызовов.


Если сообщение отправляется в другой контекст/поток, то не можешь ты ничего увидеть в обычном приложении тоже. А в описанном применении по-другому никак. Сетевой модуль или GUI-модуль должен плюнуть сообщением в асинхронню, по отношению к вызываемому, очередь и снова бежать слушать сокет или очередь сообщений GUI. Я не вижу вообще продем с отладкой в этой системе (из реальной работы такое наблюдение). Загрузи в систему только два интересующих модуля — один источник, другой приемник, и отлаживай. Ну и плюс сообщение всегда можно дополнить нужными тебе полями, например Source. Причем, подобное поле может быть как одним из типизированных полей, так и полем в мапе fields[tag, name]. Для отладочных целей никто не мешает в момент отправки сообщения дополнять его отладочными полями, скажем так:
message[Params.StackTrace] = GetStackTrace();

Причем, делается это лишь в одном месте — в кишках очереди сообщений.

А сами эти поля никто не мешает сделать типизированными:
class Params {
    public static Param<int> MinJitter;
    public static Param<bool> Dejitter;
    public static Param<float> AgcLevel;
    public static Param RecordUri;
...
}


С пустым параметром шаблона — это текстовый параметр/поле сообщения. Во время старта через рефлексию эти поля инициализируются значениями в такой манере:
Params::MinJitter = new Param<int>();

Т.е. просто создается identity типизированного аргумента (простоты ради этого не делается при объявлении). Соответственно, положить затем аргумент в сообщение и изъять из него можно будет только типизированное значение, указанное при объявлении identity аргумента.

Ну и пара основных интерфейсов:
    /// @return True to stop processing, false to try other handlers
    public interface IMessageReceiver
    {
        bool Received(Message msg);
    }

    public interface IMessageNotifier : IDisposable
    {
        void Dispatched(Message msg, bool handled);
    }


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

Еще момент — был добавлен приоритет обработчиков, чтобы получающие сообщения чаще всего (и чаще всего останавливающие дальнейший диспатчинг сообщения) были первыми. Но это мелочи лишь для поднятия эффективности. Даёт эффект только когда к системе прицепились сотни/тысячи юзеров и поднялось несколько модулей на каждое соединение.


S>Еще: как ни крути, в конце концов приходишь к тому, что алгоритм работы модулей программы построен на схеме "запрос-ответ". Синхронно ли, асинхронно ли, но так.


Да, поэтому есть механизм синхронной и асинхронной отправки сообщений. Прямо как в виднах. И есть возврат результирующего значения. Для синхроного — это просто дополнения/модификация сообщения, для асинхронного — надо подать делегат, куда придет возвращаемое сообщение (или не подать ничего для игнора).

S>А схемы вроде broadcast и notification handlers используются только в event-ах, которые не возвращают результат.


Глупости. Вот есть приложение, которое хочет установить связь, есть конечное URI, в системе загружено несколько модулей. Ты посылаешь предопределенное сообщение с этим URI, чтобы имеющиеся модули, подписанные на это предопределенное сообщение, его опознали. Кто опознал URI — может прервать цепочку обработки сообщения (опять же, прямо как в Windows) и вернуть некое новое сообщение с распаршенными полями URI и прочими характеристиками подключения.

Просто дело в том, что если расписывать всю подобную функциональность в виде некоего жирного интерфейса и его методов, то, в итоге, сколько будет сообщений, столько методов. Причем, там параметров много обычно, поэтому на каждый метод еще будешь разрабатывать структуры/классы, которые будут аргументами этих методов. Теперь для прикидки: таких методов могут быть многие сотни, а конкретные модули юзают буквально единицы/десятки сообщений. И что характерно, "области" таких методов/сообщений пересекаются, то есть ты не поделишь этот интерфейс более-менее разумно кроме как на буквально интерфейсы с одним методом. Тогда вся "типизированная" кухня будет отличаться от описанной только тем, что вместо обобщенного сообщения ты будешь использовать типизированные сообщения (структуры/классы). Не знаю, насколько это оправдано, если для 99% процентов случаев полями таких классов будут Nullable<int>, Nullable<SomeEnum> и аналогичные... Чем это отличается от показанного динамического варианта? Оно ведь не отличается даже подержкой интеллисенса, бо показанных классов Params довольно много: IaxParams, SipParams, MixerParams и т.д. на каждый прикладной раздел, т.е. пишешь SipParams-точка-выпадает список.

Ну и насчет расширяемости тут даже говорить нечего. Добавить что-либо не трогая остального — проще не бывает в текущем виде. Когда клиенту идут обновления — не надо слать обновления на всю систему, только на обновленные модули.


S>Т.е. в 99% случаев есть некий вызов с параметрами и ожидается результат именно этого вызова (а не предыдущего).


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

S>В actor-based приложениях это как-то реализовано на уровне языка/рантайма или приходится самому руками реализовывать (например, в каждом сообщении передавать уникальный id запроса и "обратный адрес", на который надо выслать ответ) ?


Дык, можно взять готовый асинхронный паттерн дотнета (он не совсем удобен, правда), или использовать свой упрощенный асинхронный паттерн. Курить эту тему самостоятельно, сорри. ))
Думаю, что с новыми асинхронными фишками дотнета, типа await, сейчас можно получить очень простой синтаксис... Хотя и был не так уж сложный.
Re[2]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 09:24
Оценка: +2 -1 :)
Здравствуйте, WolfHound, Вы писали:

WH>Акторы нарушают SRP.


Наоборот.

WH>Ибо очередь сообщений и поток исполнения не связанные между собой сущности. А акторы прибивают гвоздями одно к другому.


Вот то хорошо, что контекст актора и физический поток исполнения — это могут быть относительно независимые вещи (потоки могут эффективно переиспользоваться). Прямо как в DCOM.

WH>Это приводит к реальным проблемам, когда нужно организовать общение с несколькими акторами.

WH>Ибо вместо того чтобы создать по каналу на соседа и точно знать какой ответ пришёл от какого соседа.

Канал надо как-то создать. Источники и приемники каналов друг о друге заранее не знают. В нашей системе как раз подобным образом создавался канал. Ес-но некое медиа идет затем не через подобную систему, а через специализированные интерфейсы, которые и есть каналы.

WH>Придется в каждом ответе протаскивать отправителя и руками разбираться от кого пришёл ответ.


Не в каждом, а на этапе, который в VoIP назван signaling. А по сути — это динамическая конфигурация некоего графа каналов в ответ на динамические же пришедшие capability каждого ендпоинта.

WH>Также начинаются проблемы, если мы хотим дождаться ответа от одного актора, а ответ от другого приходит раньше.


Это нормально, например при сбросе соединения. Тебе уже не нужен тот первый ответ.

WH>Лечится это при помощи selective receive но он сам по себе создает кучу проблем.


Непонятно, о чём ты... "Концептуально" посылка сообщений ничем не отличается от асинхронных вызовов. Всё тоже самое, вид в профиль. Точно такие проблемы и точно такие способы их преодоления. См. чуть более подробно рядом: http://www.rsdn.ru/forum/philosophy/4795831.1.aspx
Автор: vdimas
Дата: 28.06.12


WH>В частности выборка сообщения из очереди O(N) от размера очереди. Те полный разбор очереди O(N^2).


Нет, очередь на то и очередь, что сообщения тупо выбираются по очереди. Даже механизм приоритетных очередей (который реально используется) нифига не O(N), а K*O(1), где K — кол-во уровней приоритета. В общем случае пары уровней достаточно для срочных сообщений.

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


))
Для примера затраты на сигналинг, в сравнении с обработкой медиа — это менее сотой доли одного %. А медиа держит сотни/тысячи подключений.


WH>Короче модель каналов из сингулярити наше все.


Еще раз, каналы надо как-то создать в заранее неопределенной среде. Согласно принципу SRP, каждый актор-модуль понятия заранее не имеет, куда он будет подключен для выполнения работы.И не должен, в этом суть. Это же альтернатива банальному DI-контейнеру в условиях, когда кол-во типов сообщений (и соответствующих типизированных интерфейсов, предназначенных исключительно для сигналинга) переваливает за сотни. Тогда DI-контейнер становится гирей на ногах, перетягивающей к себе внимание от прикладных задач.

WH>А если еще и язык поддерживает проверку протоколов, то все совсем хорошо получается.


Как раз по приведенной ссылке упомянул случай большого кол-ва nullable-значений согласно прикладной задаче. Т.е. даже привычная типизированность в условиях большого кол-ва nullable-значений не играет рояли, ведь это динамика в любом случае. Не сильно большая разница м/у if(message.TryGet(Param.Param1, out value)) vs if(message.Param1.HasValue). Всё равно ко второму варианту зачастую приделывают хелпер наподобие первого варианта, бо с ним удобнее обыгрывать сценарий значений по-умолчанию. У нас еще была такая сигнатура как раз для значений по-умолчанию:
var value = message[Param.Param1, defaultValue];

Намного удобнее в итоге, чем якобы типизированные структуры с 99% nullable полями.
Re[3]: Actor-based. Success story
От: WolfHound  
Дата: 28.06.12 10:14
Оценка: 2 (1) +1
Здравствуйте, vdimas, Вы писали:

WH>>Акторы нарушают SRP.

V>Наоборот.
Мда. Чем дальше. Тем фееричнее.
Разговаривать с тобой нет смысла.
Но проблема в том, что нас дети читают.
Так что придется разобрать глупости.

WH>>Ибо очередь сообщений и поток исполнения не связанные между собой сущности. А акторы прибивают гвоздями одно к другому.

V>Вот то хорошо, что контекст актора и физический поток исполнения — это могут быть относительно независимые вещи (потоки могут эффективно переиспользоваться). Прямо как в DCOM.
1)Ты вообще на что отвечаешь?
2)Какое отношение имеют незначительные детали реализации к модели акторов?

Ты блин даже модель системы от деталей реализации этой системы отличить не можешь.
А самое смешное то, что та модель многопоточности что я описал, может быть реализована также.

V>Канал надо как-то создать. Источники и приемники каналов друг о друге заранее не знают.

Про сингулярити не читал.

V>Не в каждом, а на этапе, который в VoIP назван signaling. А по сути — это динамическая конфигурация некоего графа каналов в ответ на динамические же пришедшие capability каждого ендпоинта.

Если не в каждом, то тебе придется делать каналы. О чем ты и пишешь.
Но при этом со мной споришь.

WH>>Также начинаются проблемы, если мы хотим дождаться ответа от одного актора, а ответ от другого приходит раньше.

V>Это нормально, например при сбросе соединения. Тебе уже не нужен тот первый ответ.
Мне виднее нужен ли мне первый ответ или нет.
Не натягивай свой частный случай на общий.

WH>>Лечится это при помощи selective receive но он сам по себе создает кучу проблем.

V>Непонятно, о чём ты...
В гугле забанили?

V>"Концептуально" посылка сообщений ничем не отличается от асинхронных вызовов. Всё тоже самое, вид в профиль. Точно такие проблемы и точно такие способы их преодоления. См. чуть более подробно рядом: http://www.rsdn.ru/forum/philosophy/4795831.1.aspx
Автор: vdimas
Дата: 28.06.12

Это ты очень примитивные задачи решаешь.
А на самом деле все гораздо сложнее, чем ты говоришь.

WH>>В частности выборка сообщения из очереди O(N) от размера очереди. Те полный разбор очереди O(N^2).

V>Нет, очередь на то и очередь, что сообщения тупо выбираются по очереди. Даже механизм приоритетных очередей (который реально используется) нифига не O(N), а K*O(1), где K — кол-во уровней приоритета. В общем случае пары уровней достаточно для срочных сообщений.
А в очереди, по которой работает selective receive выбор сообщения O(N).
А без selective receive ты не сможешь временно проигнорировать сообщение и дождаться сначала другое.
При этом, когда можно заводить произвольное количество каналов таких проблем не возникает в принципе.

V>Для примера затраты на сигналинг, в сравнении с обработкой медиа — это менее сотой доли одного %. А медиа держит сотни/тысячи подключений.

Ты опять свой примитивный частный случай раздуваешь до общего.

V>Еще раз, каналы надо как-то создать в заранее неопределенной среде. Согласно принципу SRP, каждый актор-модуль понятия заранее не имеет, куда он будет подключен для выполнения работы.

Феерия продолжается.
SRP вообще не о том.
На всякий случай SRP == single responsibility principle.

V>И не должен, в этом суть. Это же альтернатива банальному DI-контейнеру в условиях,

DI-контейнер к SRP никакого отношения не имеет.
Кроме того что DI-контейнер не должен нарушать SRP и не заниматься например рисованием кнопок на форме.

WH>>А если еще и язык поддерживает проверку протоколов, то все совсем хорошо получается.

V>Как раз по приведенной ссылке упомянул случай большого кол-ва nullable-значений согласно прикладной задаче.
Причем тут вообще nullable-значения?
Каналам до лампочки что передавать.

V>Т.е. даже привычная типизированность в условиях большого кол-ва nullable-значений не играет рояли, ведь это динамика в любом случае. Не сильно большая разница м/у if(message.TryGet(Param.Param1, out value)) vs if(message.Param1.HasValue). Всё равно ко второму варианту зачастую приделывают хелпер наподобие первого варианта, бо с ним удобнее обыгрывать сценарий значений по-умолчанию. У нас еще была такая сигнатура как раз для значений по-умолчанию:

Нормальные люди для этого используют алгебраические типы данных.
Все сразу становится очень просто и красиво.
А если посмотреть на задачу то скорей всего получится выделить вполне конкретный протокол, разбить сообщение на несколько и вообще избавится от nullable значений.

V>Намного удобнее в итоге, чем якобы типизированные структуры с 99% nullable полями.

Как, обычно не поняв о чем разговор, делаешь глобальные заявления колоссальной глупости.
Не надоело?
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Actor-based. Success story
От: sergeyt4  
Дата: 28.06.12 10:44
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, sergeyt4, Вы писали:


V>>>Сами сообщение примерно такие: { Target; Code; Map[tag, value] fields; }


S>>Меня больше всего смущает сложность отладки таких приложений.


V>Наоборот просто, ведь каждый модуль/плагин можно отлаживать независимо по очень простому интерфейсу. Скажем так, уровень атоматизации юнит тестирования модулей такой системы не сравним с обычным юнит-тестированием даже на моках. Из-за однородности интерфейса... Ты только начни писать туда хелперы для тестирования и уже не сможешь остановиться. )) Полностью декларативно и минимально выходит.


Допустим, юнит-тесты писать удобно. Но как выяснить, какие модули могут посылать сообщения или ждут сообщений от каких? В обычной программе я нажимаю Shift-F12 на методе интерфейса и получаю список мест, откуда он дергается и кем реализуется. К в актор-based программе это сделать? По коду сообщения? Как выяснить взаимосвязи модулей?

V>Если сообщение отправляется в другой контекст/поток, то не можешь ты ничего увидеть в обычном приложении тоже.

Да, с потоками это так. Но когда идет цепочка вызовов, она, как правило, в одном потоке.

Кстати, если использовать WCF, то при "шагании" внутрь сервисного метода отладчик VS2010 умеет автоматически прицепляться к процессу сервиса и останавливаться внутри вызванного метода. Причем стэк в отображается весь — и клиентский и серверный.

В общем, я понял, что actor-based модель удобна для определенного типа приложений.
Re[4]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 12:22
Оценка: -1 :)
Здравствуйте, WolfHound, Вы писали:

WH>>>Акторы нарушают SRP.

V>>Наоборот.
WH>Мда. Чем дальше. Тем фееричнее.
WH>Разговаривать с тобой нет смысла.
WH>Но проблема в том, что нас дети читают.
WH>Так что придется разобрать глупости.

Почитал... похоже на спор теоретика против всех. ))
Не читали бы вы на ночь советских газет... (С)

WH>>>Ибо очередь сообщений и поток исполнения не связанные между собой сущности. А акторы прибивают гвоздями одно к другому.

V>>Вот то хорошо, что контекст актора и физический поток исполнения — это могут быть относительно независимые вещи (потоки могут эффективно переиспользоваться). Прямо как в DCOM.
WH>1)Ты вообще на что отвечаешь?

На "прибивание гвоздями" (С).

WH>2)Какое отношение имеют незначительные детали реализации к модели акторов?


Это был твой аргумент, вот и раскрывай его.


WH>Ты блин даже модель системы от деталей реализации этой системы отличить не можешь.


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


WH>А самое смешное то, что та модель многопоточности что я описал, может быть реализована также.


Да это вообще не принципиально. Модель многопоточности диктуется выбранным способом решения конкретным задачи, а не дается сверху. Я сразу обратил внимание на то, что библиотечные очереди могут быть использованы не только на самом верхнем уровне, но и на уровне подсистем. Где-то это будет один поток выгребания из очереди и мы получаем однопоточное "приложение" в рамках подсистемы (аналог Windows GUI или COM STA), а где-то — пул потоков будет выгребать, и мы можем получить как мульти-STA, так и ThreadingNeutral — оба на эффективном механизме пула потоков. А перемещение сообщения из глобальной очреди сообщений в некую очередь внутри подсистемы — это полный аналог обычного маршалинга COM при пересечении несовместимых контекстов.


V>>Канал надо как-то создать. Источники и приемники каналов друг о друге заранее не знают.

WH>Про сингулярити не читал.

Да читали все и уже давно. Вот твой уровень обсуждения... Даже грустно... Короче, курить для примера сигналинг в VoIP-системах, чтобы понять, откуда ноги растут у задач произвольного создания каналов в гетерогенной среде протоколов. Сама механика каналов нифига не сложность, в отличии от задачи динамического построения самой системы каналов. Заодно курить цели и задачи DI-контейнеров для похожих целей.


V>>Не в каждом, а на этапе, который в VoIP назван signaling. А по сути — это динамическая конфигурация некоего графа каналов в ответ на динамические же пришедшие capability каждого ендпоинта.


WH>Если не в каждом, то тебе придется делать каналы. О чем ты и пишешь.

WH>Но при этом со мной споришь.

А чего с тобой спорить, если ты опять показываешь, что ты не в теме, а просто теоретизируешь. Но у тебя очень поверхностно выходит. Основные акценты тебе назвали, обрати на них внимание перед следующей итерацией. А ты пытаешься сместить акцент на интересные сугубо тебе вещи — на аналоги yield return из C#, которые в Сингулярити плотнее встроили в язык. Я вообще хз что там обсуждать, ведь они неинтересны с технической т.з., и к тому же, имеют известные ограничения/недостатки. Тут достаточно было одного предложения с твоей стороны "каналы Сингулярити". Всё понятно, говорить не о чем.


WH>>>Также начинаются проблемы, если мы хотим дождаться ответа от одного актора, а ответ от другого приходит раньше.

V>>Это нормально, например при сбросе соединения. Тебе уже не нужен тот первый ответ.
WH>Мне виднее нужен ли мне первый ответ или нет.
WH>Не натягивай свой частный случай на общий.

MTA на сегодня и есть общий случай, в отличие от STA. У более продвинутых получается NeutralThreading Model сверху асинхронных очередей. Уже 3-й раз я привожу аналогии, которые ты должен был бы знать. Откуда вообще берется задача маршаллинга вызовов COM даже в рамках одного процесса, не разбирался еще? Самое время.

STA — это и есть одна очередь сообщений к контексту выполнения (не к физическому потоку, а именно контексту). Это часть протокола и гарантий последовательности всех вызовов для тех самых частных случаев, которые ты по-ошибке решил назвать общими.

WH>>>Лечится это при помощи selective receive но он сам по себе создает кучу проблем.

V>>Непонятно, о чём ты...
WH>В гугле забанили?

Непонятно о чем после раскрытия деталей рядом. Даже у реактивной модели есть переходы poll/push, предлагаю покурить для чего именно используют эти переходы и в каких именно местах системы. Это напрямую по обсуждаемой теме. Заодно стоит пофантазировать, а как, собственно, эти переходы могут быть реализованы. Твои предложения?


V>>"Концептуально" посылка сообщений ничем не отличается от асинхронных вызовов. Всё тоже самое, вид в профиль. Точно такие проблемы и точно такие способы их преодоления. См. чуть более подробно рядом: http://www.rsdn.ru/forum/philosophy/4795831.1.aspx
Автор: vdimas
Дата: 28.06.12

WH>Это ты очень примитивные задачи решаешь.
WH>А на самом деле все гораздо сложнее, чем ты говоришь.

Сложнее обычной асинхронности ничего на сегодня нет. И не будет. Но на сегодня многие подводные камни давно обжеванны. Как ты думаешь, зачем в том же дотнете диспетчер сообщений выделен в отдельную сущность и почему у него несколько реализаций как под WinForms так и под WPF? Не писал еще свои диспетчеры? Или, если помнишь, коллега eao197 разрабатывал аналогичную систему для С++ и вокруг чего было больше всего обсуждений? Именно вокруг способов диспатчинга, т.е. механизма доставки сообщений. Но тут ничего интереснее STA, MTA и асинхронности на пуле потоков не придумаешь — остальное будет их комбинаторное сочетание и получающийся в итоге некий маршрут маршалинга (сорри за масло-маслянное) согласно конкретной связи апартментов с конкретными политиками. Иногда довольно-таки нетривиальный маршрут выходит.

WH>>>В частности выборка сообщения из очереди O(N) от размера очереди. Те полный разбор очереди O(N^2).

V>>Нет, очередь на то и очередь, что сообщения тупо выбираются по очереди. Даже механизм приоритетных очередей (который реально используется) нифига не O(N), а K*O(1), где K — кол-во уровней приоритета. В общем случае пары уровней достаточно для срочных сообщений.
WH>А в очереди, по которой работает selective receive выбор сообщения O(N).


Опять и снова курить отличие poll/push моделей. Пусть себе будет O(N) у тех, кто не может выбрать подходящую под задачу модель и привык писать код синхронно.


WH>А без selective receive ты не сможешь временно проигнорировать сообщение и дождаться сначала другое.


Смогу через маленьку прослойку-драйвер.
Queue privateMessages;
...
if(message.target != awaitingChannel) {
  privateMessages.enque(message);
  yeild return;
}

awaitingChannel.push(message);
...
dispatch(privateMessages);


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


WH>При этом, когда можно заводить произвольное количество каналов таких проблем не возникает в принципе.


Возникает проблема реакций на срочные сообщения по непонятно какому каналу... А твоя — ерундовая, вообще-то для C#, разруливается через yield и получаются в точности такие же каналы, как в сингулярити, через переворачивание исходного синхронного кода в автоматную модель. Но это ограниченная модель сама по себе, т.к. исходный "синхронный" код заведомо ограниченнее явно написанного асинхронного/событийного. Хотя, для некоторых несложных сценариев вполне покатит.

Я напомню, как это делалось раньше для твоих "отдельных каналов" с твоим selective receive:
— создавалось несколько невидимых окошек (ктате, посмотри в своей системе Windows, сколько прямо сейчас у тебя сидит невидимых окошек, сугубо для использования встроенного в винды механизма доставки сообщений);
— выгребание сообщений, если помнишь, по методу poll, и ты можешь именно что дожидаться сообщений на конкретном окне-канале, подавая нужный HWND;
— ты можешь выгребать произвольные сообщения, не только для конкретного окошка, тем самым умея реагировать на срочные сообщения;
— доступна как синхронная модель из-за того, что poll сообщений всегда на совести приложения, а не Windows, так же доступна событийная модель, если привязать обработчки к конкретному хендлу окна.
— потоков может быть несколько, но привязка окна к потоку — жесткая, в итоге имеем STA или мульти-STA.

В общем, фиг с ним с бесполезным теоретизированием, лучше расскажу общий подход к таким вещам при разработке довольно-сложного енжина.
— Основную сложность вижу именно в динамической природе создания связанного графа объектов (инициализация твоих каналов, если хочешь), хотя сами некоторые каналы ес-но типизированы (медиа, например, даже если это медиа передается в другие потоки — а оно всегда так на lock-free очередях). Для привычных мейнстримовый языков — такие типизированные каналы — это просто абстрактные интерфейсы, внутри которых обработчик или очередь-прокси к обработчику в другом потоке; В общем, требуется развитие идеи, заложенной в DI-контейнеры, бо они хороши только для связи примерно десятка сущностей, не более. Ну и плюс не умеют многие вещи, типа разнообразного диспатчинга м/у различными политиками контекстов.
— Платформа понятия не имеет о конкретных интерфейсах, но умеет передавать экземпляры объектов, поддерживающих требуемый интерфейс с гарантией типизированности;
— Некая полезная целевая функциональность в любом случае строго-типизированная, будь то реализация кодека, протокола или просто некоего алгоритма верификации/шифрования;
— Для работы в подобной динамической системе на каждую такую "типизированную" функциональность пишется т.н. драйвер (он у нас так и назывался Driver), в базовой реализации которого уже заложены все плюшки насчет политик диспетчеризации сообщений. Надо только отнаследоваться, выставить необходимые полики и преобразовывать обобщенные сообщения к вызовам целевых алгоритмов/объектов и обратно по событиям оборачиваемого объекта. Драйвер выходит очень "тонким", от десятков строк до ~300 строк для самого сложного в системе (по факту). Но там сложность не интенсивная, а экстенсивная, то бишь за счет кол-ва обрабатываемых сообщений, помимо основных базовых в базовой реализации драйвера. (Все-таки платформа была проблемно-ориентированной)

Сколько я смотрел сложные системы на этот счет — все они идут примерно к такому виду.



V>>Для примера затраты на сигналинг, в сравнении с обработкой медиа — это менее сотой доли одного %. А медиа держит сотни/тысячи подключений.

WH>Ты опять свой примитивный частный случай раздуваешь до общего.

V>>Еще раз, каналы надо как-то создать в заранее неопределенной среде. Согласно принципу SRP, каждый актор-модуль понятия заранее не имеет, куда он будет подключен для выполнения работы.

WH>Феерия продолжается.
WH>SRP вообще не о том.
WH>На всякий случай SRP == single responsibility principle.

Да неужели?


V>>И не должен, в этом суть. Это же альтернатива банальному DI-контейнеру в условиях,

WH>DI-контейнер к SRP никакого отношения не имеет.

Трюк DI — это и есть непременный способ достижения качественного SRP. Нельзя сузить функциональность не отвязавшись от конкретных подробностей объектов, с которыми взаимодействуешь. Но DI несет с собой нагрузку — построение графа объектов теперь внешнее и порой весьма нетривиальное... Зато максимально гибкое. В общем как в классике, за любой плюс платишь минусами в другом месте.

WH>Кроме того что DI-контейнер не должен нарушать SRP и не заниматься например рисованием кнопок на форме.


DI-контейнер должен лишь помогать решать те дополнительные задачи, которые создает DI-подход к проектированию. Я ХЗ при чем тут кнопка... Ты вообще представляешь типовые задачи DI-контейнеров? А то я ссылался на него как на нечто само-собой разумеющееся... Зря ссылался?

WH>>>А если еще и язык поддерживает проверку протоколов, то все совсем хорошо получается.

V>>Как раз по приведенной ссылке упомянул случай большого кол-ва nullable-значений согласно прикладной задаче.
WH>Причем тут вообще nullable-значения?
WH>Каналам до лампочки что передавать.

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

V>>Т.е. даже привычная типизированность в условиях большого кол-ва nullable-значений не играет рояли, ведь это динамика в любом случае. Не сильно большая разница м/у if(message.TryGet(Param.Param1, out value)) vs if(message.Param1.HasValue). Всё равно ко второму варианту зачастую приделывают хелпер наподобие первого варианта, бо с ним удобнее обыгрывать сценарий значений по-умолчанию. У нас еще была такая сигнатура как раз для значений по-умолчанию:

WH>Нормальные люди для этого используют алгебраические типы данных.
WH>Все сразу становится очень просто и красиво.

nullable и есть алгебраический тип.

WH>А если посмотреть на задачу то скорей всего получится выделить вполне конкретный протокол, разбить сообщение на несколько и вообще избавится от nullable значений.


Не получится. В сетевых протоколах предпочитают давать максимум за раз, сокращая кол-во пинг-понгов для установки связи и договоре о capability и прочих тонкостях. Поэтому 99% полей идут nullable by design. См. хотя бы ASN.1 описание протокола H.323 или семейства T.120-T.13x — там почти всё optional. Отсутствие некоего поля — это тоже важный факт, как и конкретное значение по нему.

V>>Намного удобнее в итоге, чем якобы типизированные структуры с 99% nullable полями.

WH>Как, обычно не поняв о чем разговор, делаешь глобальные заявления колоссальной глупости.
WH>Не надоело?

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

Короче, коль топикстартером вопрос был поставлен о том, стоит ли вообще использовать эту модель или нет, и спрашивалось о фактически-реализованных система, то обсуждать надо лишь их, а не фантазии... а так же интересны акценты трудоемкости и всякие следствия из обсуждаемой модели.. Что я и обсуждаю, в отличие от, приходящих сугубо языком поболтать.
Re[5]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 12:29
Оценка:
Здравствуйте, sergeyt4, Вы писали:

S>Допустим, юнит-тесты писать удобно. Но как выяснить, какие модули могут посылать сообщения или ждут сообщений от каких? В обычной программе я нажимаю Shift-F12 на методе интерфейса и получаю список мест, откуда он дергается и кем реализуется. К в актор-based программе это сделать? По коду сообщения? Как выяснить взаимосвязи модулей?


А как ты это делаешь в более простом DI-контейнере? А исопльзуешь ли вообще подход DI? Например, используешь ли ты обычные события дотнета вне WinForms (или другого GUI)? А как ты в WinForms узнаешь, кто подпишется на твоё событие? ИМХО, подпишется кто угодно...

V>>Если сообщение отправляется в другой контекст/поток, то не можешь ты ничего увидеть в обычном приложении тоже.

S>Да, с потоками это так. Но когда идет цепочка вызовов, она, как правило, в одном потоке.

Для такой простой цепочки вызовов в простых сценариях ничего сверху привычного ООП/КОП изобретать ни в коем случае не надо. Вот тут ниже я рассказал, в каком месте появляются подсистемы-акторы: http://www.rsdn.ru/forum/philosophy/4796124.1.aspx
Автор: vdimas
Дата: 28.06.12

(искать по слову драйвер)

S>Кстати, если использовать WCF, то при "шагании" внутрь сервисного метода отладчик VS2010 умеет автоматически прицепляться к процессу сервиса и останавливаться внутри вызванного метода. Причем стэк в отображается весь — и клиентский и серверный.


Ну а я просто запускал две студии — клиента и сервера, бо на WCF свет клином не сошелся. И если я поймал брекпоинт на клиенте, то просто давлю паузу на сервере и всех делов.

S>В общем, я понял, что actor-based модель удобна для определенного типа приложений.


Более того, она удобна для определенного типа сущностей в приложении. Их должно быть заведомое меньшинство, в сравнении со всеми остальными сущностями. Модель акторов — это как модель операционной системы, в которой ты запускаешь взаимодействующие "приложения". Самих приложений — очень немного, в сравнении с сумарным кол-вом сущностей внутри всех приложений.
Re[4]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 13:04
Оценка:
Здравствуйте, WolfHound, Вы писали:

Кстате, удивительно адекватный контент в вики относительно акторов:

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

...

Хьюитт был против включения требований о том, что сообщения должны прибывать в том порядке, в котором они отправлены на модель актора. Если желательно упорядочить входящие сообщения, то это можно смоделировать с помощью очереди акторов, которая обеспечивает такую функциональность. Такие очереди акторов упорядочивали бы поступающие сообщений так, чтобы они были получены в порядке FIFO. В общем же случае, если актор X отправляет сообщение M1 актору Y, а затем тот же актор X отправляет другое сообщение M2 к Y, то не существует никаких требований о том, что M1 придёт к Y раньше M2.
...
Например, акторы могут использовать конвейер обработки сообщений. Это означает, что в процессе обработки сообщения M1 актор может варьировать поведение, которое будет использоваться для обработки следующего сообщения. В частности, это означает, что он может начать обработку ещё одного сообщения M2 до завершения обработки M1. На том основании, что актору предоставлено право использования конвейера обработки сообщений, ещё не означает, что он этот конвейер обязан использовать. Будет ли сообщение конвейеризовано или нет — относится к задачам технического компромисса.

...

Идея композиции систем акторов в более крупные образования является важным аспектом модульности, которая была разработана в докторской диссертации Гуля Ага[5], позже развитой им же вместе с Ианом Мейсоном, Скоттом Смитом и Каролин Талкотт.[7]
[5] http://dspace.mit.edu/handle/1721.1/6952
[7] Г. Ага, И. Мейсон, С. Смит, К. Талкотт. Основания для вычислений акторов. Journal of Functional Programming, январь, 1993 (англ.)


Прямо 1-в-1 как получилось в нашей системе, хотя до многого дошли сами в процессе решения возникающих интересных моментов/сценариев.
Re[5]: Actor-based. Success story
От: WolfHound  
Дата: 28.06.12 13:34
Оценка:
Здравствуйте, vdimas, Вы писали:

1)Актор просто по определению это связка потока исполнения и очереди сообщений.
Как это реализовано и сколько акторов живет в одном потоке ОС не важно.
Забудь про COM, MTA, STA и прочую хрень. Это все конкретные детали реализации конкретных систем.
К модели акторов они отношения не имеют.

2)SRP не имеет никакого отношения к DI.
Ибо это универсальный принцип, который должен соблюдаться всегда.
Вне зависимости от того есть DI или нет.

3)DI к асинхронности вообще и акторам в частности не имеет отношения.
Ибо их можно использовать совместно или по отдельности.

4)Если бы ты потрудился понять о чем разговор, то ты бы не писал такие глупости.
WH>>А без selective receive ты не сможешь временно проигнорировать сообщение и дождаться сначала другое.
V>Смогу через маленьку прослойку-драйвер.
V>
V>Queue privateMessages;
V>...
V>if(message.target != awaitingChannel) {
V>  privateMessages.enque(message);
V>  yeild return;
V>}

V>awaitingChannel.push(message);
V>...
V>dispatch(privateMessages);
V>


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

6)Нет никакой проблемы создавать каналы. Ибо ендпоинты можно передавать через каналы. Ендпоинты можно передавать при создании процесса.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 13:50
Оценка: :))
Здравствуйте, Кодёнок, Вы писали:

Кё>По-настоящему серъезные минусы это

Кё>- в actor-based архитектуре очень легко получить дедлок;

Считается ровно наоборот — акторы избавляют от присущему многопоточному ООП склонности к дедлокам. Как можно получить дедлок в асинхронной среде??? Только если ты намеренно отошел от асинхронности и ожидаешь в вечном цикле некоего конкретного события синхронно. Иначе никак...


Кё>- баг, который в простой однопоточной реализации проявляется как stack overflow и немедленный краш потока, при разбитии на акторы мутирует в отжирание 100% памяти на эту самую очередь сообщений и в результате краш всего приложения (а также других приложений в системе т.к. к out of memory как оказывается никто из них никогда реально не готов);


Ну вообще в идеологии акторов сами акторы представлены очень высокоуровневыми сущностями, 99% функциональности которых не выходят за рамки этих сущностей-акторов. Соответственно, кол-во всех багов, возникающих в асинхронных протоколах, делится примерно согласно приведенной пропорции, дай бог 1% или менее.


Кё>- отлаживать их коммуникацию мне до сих пор непонятно как, кроме как писать логи.


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


Кё>Но по сравнению с трудноуловимыми race condition это пустяки, если честно.


???
Не сталкивались ни разу в своей системе. Сдается, у вас была не полноценная система акторов.


Кё>Я лично считаю что многопоточность и примитивы синхронизации — это недоразумение и каменный век, типо макроассемблера, который лишь в единичных узких местах оправдан, а будущее за message-passing concurrency.


Так и есть. Выше некоторого уровня сложности становится невозможно отследить все сценарии взаимной блокировки ресурсов. Хотя, до определенного момента можно бороться через иерархию/приоритеты блокировок. Но их легко случайно нарушить и заблокировать не в порядке иерархии/приоритета. И тогда как выход — начинаешь думать более крупными "мазками", политиками апартментов и маршрутов независимых сообщений, передаваемых асинхронно... Всё уже изобретено до нас 20 лет назад... )))

Кё>Task-based concurrency библиотеки (что то же самое) в c# и java давно уже отлично себя показывают, при правильном применении подходят почти везде.


В дотнете есть от рождения. Создай обычный объект, разметь его нужными атрибутами апартмента COM, создавай потоки, инициализируй их как STA или MTA, и используй встроенный маршаллинг, получив предварительно COM-интерфейс у объекта. Но что-то чуть более хитрое делать намного сложнее — проще написать самим аналоги диспетчеров сообщений.


Кё>Применять стоит везде, где неудобства (см. главный минус) и возможные накладные расходы не представляют проблемы.


Насчет дедлоков, повторю, поклеп. Акторы нужны для избавления от дедлоков в многопоточной среде.
Re[6]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 14:44
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>1)Актор просто по определению это связка потока исполнения и очереди сообщений.


Неверно.

Акторы — это модель асинхронного выполнения вызовов методов, больше ничего. Т.к. способы организации очередей и потоков, их взаимодействие и политика доставки сообщений не навязывается сверху, говорить о завязке одного на другого — неверно. Наоборот, это отвязка момента создания сообщения от момента доставки.


WH>Как это реализовано и сколько акторов живет в одном потоке ОС не важно.

WH>Забудь про COM, MTA, STA и прочую хрень. Это все конкретные детали реализации конкретных систем.
WH>К модели акторов они отношения не имеют.

Имеют ес-но в качестве демонстрации разнообразия способов доставки сообщений. Это был ответ на "по определению это связка потока исполнения и очереди сообщений". Нет такой связки. Акторы отличаются от обычного ООП асинхронностью и ничем больше, не оговаривая подробностей реализации асинхронности. Хотя, конкретные политики и способы диспетчеризации исследуются на уровне докторских диссертаций. См. список литературы в статье в Вики.

WH>2)SRP не имеет никакого отношения к DI.

WH>Ибо это универсальный принцип, который должен соблюдаться всегда.
WH>Вне зависимости от того есть DI или нет.

Можно узнать, что означает фраза "есть DI или нет"???

DI — это просто подход к проектированию/декомпозиции и не более. По конечному результату, то бишь по декомпозии как продукту дизайнера ПО сложно сказать, было там применено DI или нет. DI — это процесс, а не результат. С помощью этого процеса достигается лучшее SRP, это аксиома. С чем ты споришь-то?


WH>3)DI к асинхронности вообще и акторам в частности не имеет отношения.


DI как трюк разработки нет, есно, а упомянутые мною DI-контейнеры имеют самое непосредственное отношение. См. в той же статье вики тонкость насчет того, как акторы узнают друг о друге. ИМХО, это и есть самая интересная задача в акторах и она выглядит как естественное продолжение задачи, которую решают DI-контейнеры. Ты уже освежил, какую задачу решают эти контейнеры? Раньше их чаще называли IoC-контейнеры, что неграмотно (хоть и прижилось в кач-ве популярного мема... Но некоторые крупные конторы, например Microsoft, пользуются более корректной терминологией).


WH>Ибо их можно использовать совместно или по отдельности.


Трюк DI или асинхронность? Или DI-контейнеры и акторов?


WH>4)Если бы ты потрудился понять о чем разговор, то ты бы не писал такие глупости.


Да я то понимаю и просто получаю фан от наблюдения за твоей работой мысли.. скрипа шестеренок... Но не боись, как показали предыдущие обсуждения, ты довольно быстро "нащупываешь" в чем дело и начинаешь говорить более-менее предметно. Взять хотя бы ту тему о выделении памяти областями или о синхронном GC. Конкретно по этой теме — тебе надо заглянуть в тему DI-контейнеров и у тебя все части обсуждения срастутся сами собой... Гарантирую.


WH>5)В любой асинхронной системе есть точки синхронизации. И не редко нам нужно дождаться результатов в определенной последовательности.


1. Дождаться не значит блочить физический поток.
2. Без подержки срочных собщений, то бишь исключительных ситуаций — это путь к дедлоку. Как известный пример: по приходу того же WM_QUIT бесполезно в обработчике некоего окна вечно ждать некоего специального сообщения, надо тупо освобождать ресурсы и выходить.

Поэтому каждую такую последовательность можно выделить в независимый алгоритм-продолжение, дергающийся в произвольные моменты, то бишь асинхронно извне, но синхронно внутри себя. Примеры популярности использования встроенного виндового механизма для того же самого я уже приводил, запусти Spy++ и полубуйся на все эти скрытые окна WorkerW, message_loop_wnd и прочее... Но это событийная модель, а модель синхронного разворота наподобие yield в C# или аналогичных по-сути каналов сингулярити менее гибка, хотя пойдет для несложных сценариев (повторяюсь уже). И опять же, корректное освобождение ресурсов продолжений в случае простого подвисания (то бишь, больше не подаются тики на шаги продолжения) возможно только на GC. В случае же необходимости детерминированного освобождения ресурсов мне более гибким показалось использование обычной асинхронности с генерацией исключительных ситуаций на уровне входного драйвера. То бишь любой "синхронный" вызов в асинхронной среде — это ни в коем случае не блокировка физического потока, а наоборот — освобождение потока обратно в пул. Современные async/await расшириния C# как раз в правильном направлении. Сравни что происходит с yield/return. Хотя, два подхода можно комбинировать, и получать еще более компактную запись того же самого, что я расписывал без async/await.


WH>6)Нет никакой проблемы создавать каналы. Ибо ендпоинты можно передавать через каналы. Ендпоинты можно передавать при создании процесса.


Гы-гы, это звучит как аналогичное для стандартного ООП: "нет никакой проблемы соединять объекты друг с другом, просто через вызовы методов, установки св-в или через аргументы конструктора". Так для чего же тогда нужны DI-контейнеры? Особенно там, где SRP во главе угла?

Вот ты пока не проникся самой интересной задачей в акторах, считая, что доставка сообщений интересна сама по себе. Неинтересна, это очень низкоуровнево и топорно. По крайней мере у меня на ядро доставки сообщений под 3 политики ушло буквально 3 дня и практически без изменений дожило до продакшена, там нечего делать (возможно, сказался опыт клепания когда-то на VB/DCOM высокоуровневого "клея" для систем бух-учёта, с возможностями в DCOM задания аппартаментов и выделения процессов или колв-а STA-аппартаментов для работы DCOM-компонент, т.е. что происходит и для чего именно оно происходит было известно очень давно).

Хотя взаимные комбинации политик доставки в ирерархических системах акторов порождают любопытные пути прохождения сообщений. Но они любопытны сугубо из эстетических соображений, а так-то всё правильно, и на логике очередности/политики доставки сообщений сидит львиная доля прикладной логики, это неотъемлимая часть протоколов. Зато всё остальное потребовало помозговать... Но это уже было на прикладном уровне. Просто акторы — это совсем другой прикладной уровень, чем привычное ООП, надо думать в терминах общающихся процессов-приложений в гетерогенной среде, где способ общения тоже несет смысловую нагрузку. Но опять же, после многих лет написания ГУИ-приложений асинхронная модель, которая является логическим продолжением событийной, проблем не вызвала.
Re[5]: Actor-based. Success story
От: Mamut Швеция http://dmitriid.com
Дата: 28.06.12 15:07
Оценка: :))
WH>>>>Акторы нарушают SRP.
V>>>Наоборот.
WH>>Мда. Чем дальше. Тем фееричнее.
WH>>Разговаривать с тобой нет смысла.
WH>>Но проблема в том, что нас дети читают.
WH>>Так что придется разобрать глупости.

V>Почитал... похоже на спор теоретика против всех. ))

V>Не читали бы вы на ночь советских газет... (С)

Ну эта. В теории, теория сильнее практики, а на практике...

Тут Wolfhound загоняется насчет selective receive, и я даже знаю, какую ссылку он держит в загашнике. Только вот он работает уже 20 лет в промышленных масштабах, а Singularity с каналами не видно просто тупо нигде.

Но, естественно, именно это является труъ подходом.

Наверное, это тоже в тему: http://cl.ly/111R0x2R343X2d1R0739


dmitriid.comGitHubLinkedIn
Re[3]: Actor-based. Success story
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 28.06.12 15:23
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, Кодёнок, Вы писали:


Кё>>По-настоящему серъезные минусы это

Кё>>- в actor-based архитектуре очень легко получить дедлок;

V>Считается ровно наоборот — акторы избавляют от присущему многопоточному ООП склонности к дедлокам. Как можно получить дедлок в асинхронной среде??? Только если ты намеренно отошел от асинхронности и ожидаешь в вечном цикле некоего конкретного события синхронно. Иначе никак...


Ну обычно у нас не бывает возможности использовать машины с бесконечным объемом памяти, поэтому приходится использовать ограниченные очереди для акторов, а когда ограниченная очередь переполнена, она блокируется.
Re[7]: Actor-based. Success story
От: WolfHound  
Дата: 28.06.12 15:33
Оценка:
Здравствуйте, vdimas, Вы писали:

WH>>1)Актор просто по определению это связка потока исполнения и очереди сообщений.

V>Неверно.
Это прямо следует из определения по ссылке.

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


V>Имеют ес-но в качестве демонстрации разнообразия способов доставки сообщений. Это был ответ на "по определению это связка потока исполнения и очереди сообщений".

Это все детали реализации и не более того.

V>Нет такой связки. Акторы отличаются от обычного ООП асинхронностью и ничем больше, не оговаривая подробностей реализации асинхронности.

Ну, так асинхронность то как получается?
А получается она просто.
В каждом акторе живет свой поток.

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

V>DI — это просто подход к проектированию/декомпозиции и не более. По конечному результату, то бишь по декомпозии как продукту дизайнера ПО сложно сказать, было там применено DI или нет. DI — это процесс, а не результат. С помощью этого процеса достигается лучшее SRP, это аксиома. С чем ты споришь-то?

С тем что для того чтобы соблюдать SRP нужен DI контейнер.

V>DI как трюк разработки нет, есно, а упомянутые мною DI-контейнеры имеют самое непосредственное отношение. См. в той же статье вики тонкость насчет того, как акторы узнают друг о друге. ИМХО, это и есть самая интересная задача в акторах и она выглядит как естественное продолжение задачи, которую решают DI-контейнеры. Ты уже освежил, какую задачу решают эти контейнеры? Раньше их чаще называли IoC-контейнеры, что неграмотно (хоть и прижилось в кач-ве популярного мема... Но некоторые крупные конторы, например Microsoft, пользуются более корректной терминологией).

Я это лучше тебя знаю.

WH>>4)Если бы ты потрудился понять о чем разговор, то ты бы не писал такие глупости.

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

V>скрипа шестеренок... Но не боись, как показали предыдущие обсуждения, ты довольно быстро "нащупываешь" в чем дело и начинаешь говорить более-менее предметно. Взять хотя бы ту тему о выделении памяти областями или о синхронном GC.

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

V>1. Дождаться не значит блочить физический поток.

Опять путаешь поток ОС и поток актора. Это разные вещи.
Акторы про потоки ОС нихрена не знают. Ибо это деталь реализации. Не более того.

V>2. Без подержки срочных собщений, то бишь исключительных ситуаций — это путь к дедлоку. Как известный пример: по приходу того же WM_QUIT бесполезно в обработчике некоего окна вечно ждать некоего специального сообщения, надо тупо освобождать ресурсы и выходить.

А это автору процесса решать, что нужно делать.
Никто не мешает ждать более одного сообщения из разных каналов. Это если не маяться дурью с акторами.
А в случае с акторами ты описал selective receive.

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

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

V>Но это событийная модель, а модель синхронного разворота наподобие yield в C# или аналогичных по-сути каналов сингулярити менее гибка, хотя пойдет для несложных сценариев (повторяюсь уже).

Модель сингулярити является строгим надмножеством акторов.

V>И опять же, корректное освобождение ресурсов продолжений в случае простого подвисания ...

И ты опять завис на деталях реализации.
Леса не видишь.

V>Гы-гы, это звучит как аналогичное для стандартного ООП: "нет никакой проблемы соединять объекты друг с другом, просто через вызовы методов, установки св-в или через аргументы конструктора". Так для чего же тогда нужны DI-контейнеры? Особенно там, где SRP во главе угла?

Так они и не нужны.
Это костыль для ООП.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Actor-based. Success story
От: WolfHound  
Дата: 28.06.12 15:41
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Тут Wolfhound загоняется насчет selective receive, и я даже знаю, какую ссылку он держит в загашнике. Только вот он работает уже 20 лет в промышленных масштабах,

Ты так говоришь как будто в той ссылке не правда, написана.
И это люди нарвались на практике. И напридумывали кучу подходов как это побороть.

M>а Singularity с каналами не видно просто тупо нигде.

Пошла демагогия.

M>Но, естественно, именно это является труъ подходом.

Это подход с точки зрения модели системы является более устойчивым к всяким бякам.
В частности он не сваливается в O(N^2) на ровном месте.

M>Наверное, это тоже в тему: http://cl.ly/111R0x2R343X2d1R0739

Это намек на то, что я не способен писать продакшен код?
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 16:07
Оценка:
Здравствуйте, Lazin, Вы писали:


L>Ну обычно у нас не бывает возможности использовать машины с бесконечным объемом памяти, поэтому приходится использовать ограниченные очереди для акторов, а когда ограниченная очередь переполнена, она блокируется.


Да, поэтому рядом я написал:

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


Этот момент как-то не на поверхности, но его быстро обнаруживаешь. Но на уровне конкретного модуля, который не успевает разгребать личные сообщения, затем уже можно делать диагностику. И кстати, если очередь построена на интрузивном способе, без дополнительных узлов-носилетей логики списка, какой смысл ограничивать ее длину? Если сообщение УЖЕ создано, (а оно обязательно создано ПЕРЕД отсылкой) то прилепить ее в конец такой очереди ничего не стоит.


========================
Например, если речь об асинхронном логировании при максимальном уровне логгирования. Тогда надо как-то изворачиваться, например, ренедрить лог-сообщения в буфер в памяти предварительно, т.е., чтобы кол-во операций IO не соответствовало 1:1 к кол-ву сообщений логирования, а записывать их пачками с неким коэф (брали порядка тысячи). Заметно снижает нагрузку на систему в целом. И вообще, вот этот способ передачи "пачками", даже когда речь о передаче сообщений м/у потоками — он самый эффективный, бо постоянное обращение к АПИ ОС или даже просто interlocked-операциям в одном месте снижает эффективность обращения к совсем другому АПИ ОС в другом месте. Например, за одну операцию на lock-free очереди разгребающий поток может получить все имеющиеся сообщения на данный момент (просто голову списка, обнулив shared-переменную через CAS), и потом разбирать пачку сообщений в цикле из локальной переменной-курсора без каких-либо тяжеловесных interlocked-операций. Если примененаа фильтрация этой пачки сообщений, то результат фильтрации чанка сообщений так же лучше прилепить в другую очередь целиком через одну interlocked операцию, вместо "ленивой" фильтрации и посылки резльтата в такую очередь по 1-му сообщению.
Re[8]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 16:08
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>>>1)Актор просто по определению это связка потока исполнения и очереди сообщений.

V>>Неверно.
WH>Это прямо следует из определения по ссылке.
WH>

WH>В компьютерных науках модель акторов представляет собой математическую модель параллельных вычислений, которая трактует понятие «актор» как универсальный примитив параллельного численного расчёта: в ответ на сообщения, которые он получает, актор может принимать локальные решения, создавать новых акторов, посылать свои сообщения, а также устанавливать, как следует реагировать на последующие сообщения.


Давай на пальцах,а то непонимайт, где же тут "прямо"?
Re[7]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 16:30
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

WH>Это подход с точки зрения модели системы является более устойчивым к всяким бякам.

WH>В частности он не сваливается в O(N^2) на ровном месте.

Чтобы оно сваливалось в O(N^2), надо чтобы адрес каждый раз получался минимум за O(N) и сообщение доставлялось (т.е. ресолвился адрес) тоже за O(N), где N — кол-во акторов... а так-то обе операции выполнимы за O(1).

Цимус в том, что нет никакого смысла посылать сообщение конкретному каналу в общем случае. Даже если в Сингулярити это на уровне языка видится именно так, реально это может происходить не так. Асинхронная отсылка может идти в общую очередь с привязанным идентификатором канала, а эта очередь затем может разгребаться на пуле потоков. Почему так? Предлагаю порассуждать на предмет как времени жизни каналов, так и на предмет того, что канал вовсе не обязан иметь выделенный физический поток-обработчик сообщений. Асинхронная модель поверх событийной (то бишь на пуле потоков) хороша тем, что не требует обязательного физического потока на каждый актор. Хотя, никто не запрещает акторам создавать такие потоки для своих внутренних нужд. Просто я не представляю работу на каналах обработчиков хотя бы для тысячи подключений, если к каждому подключению привязывается минимум 5 акторов для логики всего приложения...

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

И на последок как пример — асинхронный ввод/вывод в виндах в сокеты. Сообщения отсылаются в одну "точку входа" с идентификатором сокета. Очередь на каждый физический интерфейс унутре одна (она доступна какому-нить драйверу протокола сверху интерфейса), это точно, и разгребается она через алгоритмы QoS или кастомные драйверы с той же целью. Ничего быстрее в природе на сегодня не существует. Ес-но никаких O(N^2) нет, это выдумки или примеры неудачных решений в лоб, типа пузырьковых сортировок. Любой адрес можно спроектировать так, чтобы ресолвинг по нему шел за O(1).


M>>Наверное, это тоже в тему: http://cl.ly/111R0x2R343X2d1R0739

WH>Это намек на то, что я не способен писать продакшен код?

Скорее намек на то, что в последнее время ты больше обсуждаешь несуществующие в реальном воплощении и необкатанные на практике вещи.
Re[6]: Actor-based. Success story
От: sergeyt4  
Дата: 28.06.12 16:53
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, sergeyt4, Вы писали:


V>А как ты это делаешь в более простом DI-контейнере? А исопльзуешь ли вообще подход DI? Например, используешь ли ты обычные события дотнета вне WinForms (или другого GUI)? А как ты в WinForms узнаешь, кто подпишется на твоё событие? ИМХО, подпишется кто угодно...


В WinForms все просто — все события от контролов обрабатываются в самой форме. т.е. она — единственный подписчик своих контролов. Вне форм события мы не используем. Именно потому что неизвестно, кто на них подпишется, и глядя на метод никогда не догадаешься, что он, оказывается, является обработчиком события от определенного класса. Мы используем вместо этого callback-интерфейс с одним методом. По нему легко отыскать подписчиков. (По сути event — это и есть интерфейс с одним методом, но анонимный.)

Используем ли мы подход DI? трудно сказать. Возможно и используем, не зная, что теперь это так называется.

Но идеология приложения, раздробленного на миллион независимых запчастей, которые чудесным образом собираются в одно при запуске, меня не устраивает. В нем крайне сложно разобраться — кто с кем и зачем взаимодействует, чтобы потом добавлять новый функционал или менять старый. Видимо, нужна очень подробная документация. (Но кто ее поддерживать в актуальном состоянии-то будет?) Наши приложения конечно не монолитны, но и не состоят из большого числа мелких "атомов", а скорее модулей. И эти модули явно регистрируются на старте приложения. Так что всегда можно средствами VS найти какой сервис будет активирован при запросе какого-либо интерфейса. Никаких регистраций в конфиг-файлах, только в коде.
Re[5]: Actor-based. Success story
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 28.06.12 17:27
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, Lazin, Вы писали:



L>>Ну обычно у нас не бывает возможности использовать машины с бесконечным объемом памяти, поэтому приходится использовать ограниченные очереди для акторов, а когда ограниченная очередь переполнена, она блокируется.


V>Да, поэтому рядом я написал:

V>

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

Сразу выгребать оказывается надо, ты посмотри на него! Допустим у нас есть акторы Foo и Bar. Foo посчитал что-то и пытается записать это в очередь Bar, но она переполнена, потому что Bar не забирает оттуда сообщения, а не забирает он их оттуда потому что не может записать сообщение в очередь Foo, который ... В принципе цепочка может быть произвольной длины и даже может пересекать границы отдельных машин. Нет ничего невозможного

V>Этот момент как-то не на поверхности, но его быстро обнаруживаешь. Но на уровне конкретного модуля, который не успевает разгребать личные сообщения, затем уже можно делать диагностику. И кстати, если очередь построена на интрузивном способе, без дополнительных узлов-носилетей логики списка, какой смысл ограничивать ее длину? Если сообщение УЖЕ создано, (а оно обязательно создано ПЕРЕД отсылкой) то прилепить ее в конец такой очереди ничего не стоит.

Смысл ограничивать длину в том, чтобы клиент, который смог добавить сообщение в очередь, в том случае если ему не мешать, добавит туда еще одно и еще... Bounded очереди это простой и эффективный способ организовать back-pressure на producer-а.

V>========================

V>Например, если речь об асинхронном логировании при максимальном уровне логгирования. Тогда надо как-то изворачиваться, например, ренедрить лог-сообщения в буфер в памяти предварительно, т.е., чтобы кол-во операций IO не соответствовало 1:1 к кол-ву сообщений логирования, а записывать их пачками с неким коэф (брали порядка тысячи). Заметно снижает нагрузку на систему в целом. И вообще, вот этот способ передачи "пачками", даже когда речь о передаче сообщений м/у потоками — он самый эффективный, бо постоянное обращение к АПИ ОС или даже просто interlocked-операциям в одном месте снижает эффективность обращения к совсем другому АПИ ОС в другом месте. Например, за одну операцию на lock-free очереди разгребающий поток может получить все имеющиеся сообщения на данный момент (просто голову списка, обнулив shared-переменную через CAS), и потом разбирать пачку сообщений в цикле из локальной переменной-курсора без каких-либо тяжеловесных interlocked-операций. Если примененаа фильтрация этой пачки сообщений, то результат фильтрации чанка сообщений так же лучше прилепить в другую очередь целиком через одну interlocked операцию, вместо "ленивой" фильтрации и посылки резльтата в такую очередь по 1-му сообщению.
То, что ты описал, зовется алгоритмом Нагла, ему сто лет в обед, но применение этого алгоритма для создания lock-free очереди, это что-то новое для меня
Re[3]: Actor-based. Success story
От: Кодёнок  
Дата: 28.06.12 18:55
Оценка:
Здравствуйте, vdimas, Вы писали:

Кё>>- в actor-based архитектуре очень легко получить дедлок;

V>Считается ровно наоборот — акторы избавляют от присущему многопоточному ООП склонности к дедлокам. Как можно получить дедлок в асинхронной среде??? Только если ты намеренно отошел от асинхронности и ожидаешь в вечном цикле некоего конкретного события синхронно. Иначе никак...

Например объект выслал асинхронное сообщение и ждет ответа, а клиент умер и не отвечает. Или ждет в свою очередь другого ответа, который не будет выслан пока этот ответ не придет. Или из-за бага (программист забыл отправить ответ в ветке else) — при этом сам актер остается жив и продолжает отвечать другим, и просто вот этого конкретного клиента он своим багом “подвесил”. Дедлоки там не такие, как в многопоточности, не обязательно приводящие к подвисанию всей системы, и от этого не всегда сразу заметны. В актерах дедлок это ошибка в архитектуре, сделать ее легко.

Кё>>Но по сравнению с трудноуловимыми race condition это пустяки, если честно.

V>???
V>Не сталкивались ни разу в своей системе. Сдается, у вас была не полноценная система акторов.

Я имел ввиду по сравнению с race condition при многопоточности. В актерах само собой их не бывает.
Re[2]: Actor-based. Success story
От: Кодёнок  
Дата: 28.06.12 19:12
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Короче модель каналов из сингулярити наше все.

WH>А если еще и язык поддерживает проверку протоколов, то все совсем хорошо получается.

Эта модель называется Communicating Sequential Processes и они с актерами взаимозаменяемы, одно можно реализовать через другое. Каналы например моделируются как отдельные актеры с собственной очередью сообщений, и все, никакого протаскивания сендера и можно спрашивать их в произвольном порядке и контроллировать последовательность и статически анализировать. И наоборот, беспорядочное месиво сообщений в CSP моделируется самоограничением в один канал на процесс, который будет принимать все данные. Все проблемы которые ты описал это неумение готовить.
Re: Actor-based. Success story
От: rfq  
Дата: 28.06.12 19:15
Оценка: 7 (4)
Здравствуйте, Буравчик, Вы писали:

Б>Какие языки/библиотеки использовались?

Б>Удобно ли сопровождать (понимать, расширять, изменять) такие системы?
Б>Какие есть минусы и плюсы actor-based?
Б>Для чего actor-based стоит применять, а для чего нет?


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

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

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

Основной плюс dataflow — распараллеливание на все наличное число процессоров без изменение программы. Минус — усложнение отладки, когда что-то виснет, и не сразу понятно, почему.
Re[3]: Actor-based. Success story
От: WolfHound  
Дата: 28.06.12 19:42
Оценка:
Здравствуйте, Кодёнок, Вы писали:

Кё>Эта модель называется Communicating Sequential Processes и они с актерами взаимозаменяемы, одно можно реализовать через другое. Каналы например моделируются как отдельные актеры с собственной очередью сообщений, и все, никакого протаскивания сендера и можно спрашивать их в произвольном порядке и контроллировать последовательность и статически анализировать. И наоборот, беспорядочное месиво сообщений в CSP моделируется самоограничением в один канал на процесс, который будет принимать все данные. Все проблемы которые ты описал это неумение готовить.

Конечно. Конечно.
А еще это можно организовать на мютексах, семафорах и черт знает, чем еще.
Только по запросу selective receive ссылка на его проблемы висит второй в гугле. А это что-то да значит.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 20:03
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>В каждом акторе живет свой поток.


"Поток" может быть логический, примерно как поток событий для одного окошка GUI.


WH>То что некоторые рантаймы могут шарить один поток ОС между несколькими акторами или перекидывать один актор между несколькими потоками ОС не меняет того что у каждого актора есть свой личный поток в котором происходит вся работа с состоянием актора.


Ну и чем это отличается от обычной событийной модели с т.з. конкретного актора? Если низлежащая система, например, гарантирует, что конкретному актору приложения будут приходить ровно по 1-му, и следующее не придет до тех пор, пока не вернется предыдущий вызов...

Например, акторы могут использовать конвейер обработки сообщений. Это означает, что в процессе обработки сообщения M1 актор может варьировать поведение, которое будет использоваться для обработки следующего сообщения. В частности, это означает, что он может начать обработку ещё одного сообщения M2 до завершения обработки M1. На том основании, что актору предоставлено право использования конвейера обработки сообщений, ещё не означает, что он этот конвейер обязан использовать. Будет ли сообщение конвейеризовано или нет — относится к задачам технического компромисса.


В общем, от привычной событийной модели сам код актора отличается аж ничем, подробности даются инфраструктурой, но эти подробности не являются чем-то незначащими. Считай это еще одним взглядом на способ проектирования задач, где проектирование начинается с логики/политики доставки сообщений. Очень подходит к системам, где слово "протокол" не пустой звук. Самое оно.


V>>DI — это просто подход к проектированию/декомпозиции и не более. По конечному результату, то бишь по декомпозии как продукту дизайнера ПО сложно сказать, было там применено DI или нет. DI — это процесс, а не результат. С помощью этого процеса достигается лучшее SRP, это аксиома. С чем ты споришь-то?

WH>С тем что для того чтобы соблюдать SRP нужен DI контейнер.

ОМГ... Издеваешься? Рассказываю медленно... Чтобы соблюдать SRP зачастую приходится применять процесс IoC, который транзитивно ведет к последующему обязательному DI. Я лишь указал начальные и конечные точки этого момента в процесе проектирования ООП-архитектуры, подразумевая, что ты и так должен был должен знать. Контейнер DI не является обязательным, ес-но, т.к. в жесткой архитектуре граф объектов можно построить руками. Ключевое во всём этом было то, что в технике DI граф строят не сами объекты в своих конструкторах, а некий внешний по отношению к объектам код. Я лишь поделился тем наблюдением, что заметной частью решения (то бишь трудоемкости) в реальном проекте оказались такие задачи, которые близки по-смыслу к задачам, решаемым DI-контейнерами. Почему и сослался на него, чтобы не расписывать подробно все эти задачи. В подобных контейнерах (напомню, если тебе настолько лень освежить) происходит преобразование декларативного описания зависимостей объектов в физический их граф. Т.е. при создании некоего целевого объекта DI-контейнер находит и ресолвит все зависимости к нему, создавая зависимые нужные объекты с свойствами для конкретно этой зависимости, к которым опять же ресолвятся зависимости и так рекурсивно/итеративно. Гибкости добавляет привязка зависимостей к контекстам. В терминах DI-контейнеров контексты — это не контексты исполнения, как в COM или дотнете, это как отдельные неймспейсы для самих зависимостей, то бишь много DI-контейнеров в одном. (Там еще много тонкостей, поиском по этому сайту найдешь подробные обсуждения на эту тему)

Просто удалось подобную функциональность реализовать с помощью той же самой подсистемы асинхронной передачи сообщений, бо у нас нет возможности и/или надобности "физически" подключать объекты напрямую друг к другу через ссылочные типы данных.


V>>DI как трюк разработки нет, есно, а упомянутые мною DI-контейнеры имеют самое непосредственное отношение. См. в той же статье вики тонкость насчет того, как акторы узнают друг о друге. ИМХО, это и есть самая интересная задача в акторах и она выглядит как естественное продолжение задачи, которую решают DI-контейнеры. Ты уже освежил, какую задачу решают эти контейнеры? Раньше их чаще называли IoC-контейнеры, что неграмотно (хоть и прижилось в кач-ве популярного мема... Но некоторые крупные конторы, например Microsoft, пользуются более корректной терминологией).

WH>Я это лучше тебя знаю.

Угу, всё понимаю, но сказать не могу...


WH>>>4)Если бы ты потрудился понять о чем разговор, то ты бы не писал такие глупости.

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

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

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


WH>Я просто нахожусь на более высоком уровне и вижу лес, а не деревья.


Пока что ты увидел вообще одно-единственное дерево — это собственное представление об асинхронности. Ты не застал DOS и явное управление прерываниями? Как же так оно раньше работало асинхронно вообще без выделенных потоков?

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


V>>скрипа шестеренок... Но не боись, как показали предыдущие обсуждения, ты довольно быстро "нащупываешь" в чем дело и начинаешь говорить более-менее предметно. Взять хотя бы ту тему о выделении памяти областями или о синхронном GC.

WH>То, что я говорил в той теме я понял несколько лет назад.
WH>Только ты так и не понял, что именно я говорю.

Это ты мой пример не понял. Ты ведь по-сути предложил создавать фиктивный объект с предопределенными капабилитями, утверждая, что это избавит от явных объектов-аллокаторов, введение которых в модель и составляет якобы "ручное" управление памятью (хотя там автоматическое ес-но, просто вводится зависимость от экземпляра аллокатора). Но за своим "лесом" ты не увидел того дерева, что этот фиктивный объект будет играть в дизайне точно такую же роль, как экземпляр аллокатора. Как говорится, фейсом об тейбл. Надо же было решить эту задачу точно так же, разве что через синтаксический сахарок и претендовать на новизну и якобы отсутствие "ручного управления"... Был разачарован, увы... Любое ручное управление при наличии соотв. библиотек выглядит как декларативные зависимости, ничем не хуже синтаксического сахарка. И ведь озвучивал сие многократно, чтобы ты не попал в собственную ловушку... И Всё-равно попал... Потому что лучше выражать свои намеки явно, не затягивая фазу построения умного лица.


V>>1. Дождаться не значит блочить физический поток.

WH>Опять путаешь поток ОС и поток актора. Это разные вещи.
WH>Акторы про потоки ОС нихрена не знают. Ибо это деталь реализации. Не более того.

V>>2. Без подержки срочных собщений, то бишь исключительных ситуаций — это путь к дедлоку. Как известный пример: по приходу того же WM_QUIT бесполезно в обработчике некоего окна вечно ждать некоего специального сообщения, надо тупо освобождать ресурсы и выходить.

WH>А это автору процесса решать, что нужно делать.

Чтобы ему решать, у него должна быть возможность выбирать. Если у тебя есть неблокирующие или асинхронные сокеты, то получить из них синхроннеы несложно, в отличие от наоборот, где придется асинхронную архитектуру городить ручками. Так же и для акторов — механизм доставки должен быть достаточно гибким, чтобы позволять выбирать или делать перевороты push<==>poll, как раз с целью фильтрации или упорядочивания сообщений (или дополнительного внутреннего роутинга и мало ли чего еще). Считай это разделением логики на логику совсем высокого уровня и на подробности. Логика самого высокого уровня хорошо работает как событийная модель из-за гибкости, универсальности и несклонности к дедлокам. Низкого уровня логика вполне может работать как набор синхронных poll-алгоритмов-продолжений (по крайней мере в синтаксисе языка на твоих каналах или yield return в C#), хотя извне это будет ес-но такой же push внутри poll самого высокго уровня текущего контекста исполнения (угу, именно такое оно — реактивное программирование изнутри, poll-циклы генерируют push сигналов). Хотя, по слухам, доносящимся из реактивного программирования, даже для низкого уровня push всё более интересен, а poll используется исключительно во внутренних механизмах пересечения контекстов, нейтральных к конкретной прикладной логике.

WH>Никто не мешает ждать более одного сообщения из разных каналов. Это если не маяться дурью с акторами.


В событийной модели это дается из коробки. Только мы всё еще имеем дело с акторами и не паримся...

WH>А в случае с акторами ты описал selective receive.


Нет, я показал, что O(N) для selective receive в случае ожидания одного сообщения — это бред сивой кобылы. Хотя, если КАЖДОЕ сообщение доставать по selective receive, то да-а-а... то нафига тебе асинхронность вообще? При чем тут тогда акторы?

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

WH>Те мы дожидаемся, когда поток актора зависнет на ожидании следующего сообщения и вызываем код для данного сообщения.
WH>Правда, что делать в твоей моделе если актор в данный момент не готов принять это сообщение загадка.

Да я вижу, что асинхронность вообще для тебя загадка... А что я делаю, если у меня есть данные, а сокет еще не готов их принять? Неужели загадка? Некоторые так и ждут бесконечно на сокете, что порой провоцирует интересный пространственный дедлок двух компьютеров (!!!), получателя и отправителя. Лечил я и такое в синхронном программировании. Оба ендпоинта насытили свои стеки TCP и оба ждали завершения синхронной отправки данных, а выгребать сокеты некому. Потому что шел синхронный обмен достаточно большими по размеру сообщениями (порядка полумегабайт). Вот тебе смешной "пространственный" дедлок. Асинхронность+событийная модель всё это лечит на раз.

V>>Но это событийная модель, а модель синхронного разворота наподобие yield в C# или аналогичных по-сути каналов сингулярити менее гибка, хотя пойдет для несложных сценариев (повторяюсь уже).

WH>Модель сингулярити является строгим надмножеством акторов.

Как тут говорят: "учу читать, дорого"...

Вообще-то речь была о развороте синхронного исходного кода в событийный/асинхронный. Это модель не сингулярити, а конкретного компилятора + низлежащего некоего механизма. Так вот, ограничения не в модели передачи сообщений как таковой (об этом речь не шла), а в том, что исходный синхронный код (как и его аналог yield return в C#) имеет ограничения. Если охота без ограничений — это надо не пользоваться подобными синтаксическими плюшками, а пользовать тот же IEnumerable-интерфейс напрямую или же вызывать АПИ твоей Сингулярити напрямую без поддержки каналов в синтаксисе языка... От существующих других асинхронных АПИ это ничем не будет отличаться, увы. Пайпы известны мильон лет. В т.ч. неблокирующие.

V>>И опять же, корректное освобождение ресурсов продолжений в случае простого подвисания ...

WH>И ты опять завис на деталях реализации.
WH>Леса не видишь.

Э нет, по вопросам корректной работы "продолжений" народ диссеры пишет, это нифига не незначащие детали. И как раз актуально это всё лишь в асинхроной среде. Львиная доля прикладной логики автоматом переезжает на инфраструктуру за счет комбинаторного сочетания политик взаимодействующих подсистем.


V>>Гы-гы, это звучит как аналогичное для стандартного ООП: "нет никакой проблемы соединять объекты друг с другом, просто через вызовы методов, установки св-в или через аргументы конструктора". Так для чего же тогда нужны DI-контейнеры? Особенно там, где SRP во главе угла?

WH>Так они и не нужны.
WH>Это костыль для ООП.

Нужны-нужны. Спроси у АВК, он тебе растолкует, если не понимаешь. Это считай полу-Пролог. Иногда ручки устанут объекты вручную соединять, легче декларативно указать зависимости. Особенно если такое построение неизвестно в compile-time. Кстати, для не-ООП я подобного инструмента не видел, везде еще больше ручками приходится. Если речь не о самом Прологе, есно.
Re[7]: Actor-based. Success story
От: Mamut Швеция http://dmitriid.com
Дата: 28.06.12 20:35
Оценка:
M>>Тут Wolfhound загоняется насчет selective receive, и я даже знаю, какую ссылку он держит в загашнике. Только вот он работает уже 20 лет в промышленных масштабах,
WH>Ты так говоришь как будто в той ссылке не правда, написана.
WH>И это люди нарвались на практике. И напридумывали кучу подходов как это побороть.

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

M>>а Singularity с каналами не видно просто тупо нигде.

WH>Пошла демагогия.

Пошли факты

M>>Но, естественно, именно это является труъ подходом.

WH>Это подход с точки зрения модели системы является более устойчивым к всяким бякам.
WH>В частности он не сваливается в O(N^2) на ровном месте.

Уже и фантазии про ровные места пошли


M>>Наверное, это тоже в тему: http://cl.ly/111R0x2R343X2d1R0739

WH>Это намек на то, что я не способен писать продакшен код?

Это намек на то, что пропагандируемые тобой подходы на практике днем с огнем не.


dmitriid.comGitHubLinkedIn
Re[6]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 20:42
Оценка:
Здравствуйте, Lazin, Вы писали:

V>>

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

L>Сразу выгребать оказывается надо, ты посмотри на него!

Не понял юмора. Я это написал рядом фактически сразу как обнаружились заинтересованные собеседники.

L>Допустим у нас есть акторы Foo и Bar. Foo посчитал что-то и пытается записать это в очередь Bar, но она переполнена, потому что Bar не забирает оттуда сообщения, а не забирает он их оттуда потому что не может записать сообщение в очередь Foo, который ... В принципе цепочка может быть произвольной длины и даже может пересекать границы отдельных машин. Нет ничего невозможного


Ты не поверишь, но этот сценарий тоже был упомянут: http://www.rsdn.ru/forum/philosophy/4796651.1.aspx
Автор: vdimas
Дата: 29.06.12

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


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


L>Смысл ограничивать длину в том, чтобы клиент, который смог добавить сообщение в очередь, в том случае если ему не мешать, добавит туда еще одно и еще... Bounded очереди это простой и эффективный способ организовать back-pressure на producer-а.


Гы, ты описал простой и эффективный способ достичь банального дедлока и ничего больше. Это профанация любой асинхронности как она есть, ведь превращаешь асинхронный вызов в синхронный. Один тебе актуальный намек на эту тему: в протоколах VoIP в сигналинге бывают команды на уменьшение трафика и прочая дидагностика. Заметил как реагирует кач-во звука в Скайпе при изменении условий связи? Его протокол динамически меняет кодеки.


V>>========================

V>>Например, если речь об асинхронном логировании при максимальном уровне логгирования. Тогда надо как-то изворачиваться, например, ренедрить лог-сообщения в буфер в памяти предварительно, т.е., чтобы кол-во операций IO не соответствовало 1:1 к кол-ву сообщений логирования, а записывать их пачками с неким коэф (брали порядка тысячи). Заметно снижает нагрузку на систему в целом. И вообще, вот этот способ передачи "пачками", даже когда речь о передаче сообщений м/у потоками — он самый эффективный, бо постоянное обращение к АПИ ОС или даже просто interlocked-операциям в одном месте снижает эффективность обращения к совсем другому АПИ ОС в другом месте. Например, за одну операцию на lock-free очереди разгребающий поток может получить все имеющиеся сообщения на данный момент (просто голову списка, обнулив shared-переменную через CAS), и потом разбирать пачку сообщений в цикле из локальной переменной-курсора без каких-либо тяжеловесных interlocked-операций. Если примененаа фильтрация этой пачки сообщений, то результат фильтрации чанка сообщений так же лучше прилепить в другую очередь целиком через одну interlocked операцию, вместо "ленивой" фильтрации и посылки резльтата в такую очередь по 1-му сообщению.

L>То, что ты описал, зовется алгоритмом Нагла, ему сто лет в обед, но применение этого алгоритма для создания lock-free очереди, это что-то новое для меня


Нагль малость для другого, для увеличения полезной доли в трафике. Ведь, передавая по 1-му символу с учетом всех заголовков IP и низлежащего транспорта (ethernet или ISDN), мы получаем долю полезной нагрузки менее 1%. А здесь идет речь о кол-ве вызовов АПИ ОС. Мало того, что каждый вызов ОС, даже холостой, даже на простейшем примитиве ядерной синхронизации — семафоре, занимает сотни ns на моей почти топовой машине, дык еще после самого вызова происходит некий штраф на эффективность выполнения последующего юзерского кода (добавляющий порядка 100-200ns в общем), скорее всего из-за смены контекстов виртуальной памяти туда-сюда. Т.е. эти бесполезные ~1us на сообщение предлагалось размазать на много их. За ту же стоимость 1us можно отрендерить порядка нескольких мегабайт лога в памяти, если руки правильно растут.

Ну и ты не заметил еще важную вещь, никак к Наглю не относящуюся: ты можешь регулярно вызывать одни аспекты АПИ ОС из одного потока на многоядерной машине, скажем, вызывать в цикле простой опрос времени, а тормозить может где-то в совсем другом месте, то бишь минимальная стоимость ядерных вызовов ОС на совсем других потоках и ядрах процессора из-за тех первых вызовов возрастает. ИМХО, где-то что-то в процессе ядерных вызовов синхронизируется или постоянно обновляются данные, которые обязательно шарятся. Причем, на Линухах это проявляется ярче, чем в последних виндах (7-ка). Т.е. минимизировать кол-во ЛЮБЫХ вызовов АПИ ОС — благодарная задача само по себе. (Например, поэтому пришлось отказаться от потоковой библиотеки С++)

Ну и interlocked-операции тоже, хоть дешевле, но добавляют штрафов к эффективности кеша и сбрасывают конвейеры, поэтому максимум пропускной способности на межпотоковых lock-free очередях удалось выжать только в сценарии, когда одну очередь разгребает один поток и он "забирает" каждый раз на "свою сторону" все накопившиеся на текущий момент сообщения. А балансировка нагрузки в этом сценарии наиболее эффективна по модели master-slave потоков, где мастер-поток единолично выгребает ту самую очередь и посылает другим рабочим потокам сообщения только в случае, если сам плохо справляется, то бишь когда размеры забираемых каждый раз пачек возрастают. Ес-но для нормальной работы всей системы никакой тупой bounding не пойдет. Курить ПИД-управление. Реагировать, когда очередь уже насытилась, поздно — почки уже отлетели. Надо следить за производными и интегралом, то бишь средней нагрузкой и динамикой на её фоне, а обратная пропорциональная связь задает коэф. жесткости управления... Кстате, как раз на ПИД делал де-джиттер для миксера VoIP. Много потоков шлют пакеты потоку-миксеру, который регулирует длину линии задержки в зависимости от динамики условий. Для диспатчинга сообщений делал чуть более простое управление, только ИП, без Д, но там нагрузка многократно меньше, так что хватало простого сглаживания средней нагрузки и обратной пропорциональной связи для принятия решений, сколько дополнительных потоков брать из пула.
Re[7]: Actor-based. Success story
От: vdimas Россия  
Дата: 28.06.12 21:48
Оценка:
Здравствуйте, sergeyt4, Вы писали:

V>>А как ты это делаешь в более простом DI-контейнере? А исопльзуешь ли вообще подход DI? Например, используешь ли ты обычные события дотнета вне WinForms (или другого GUI)? А как ты в WinForms узнаешь, кто подпишется на твоё событие? ИМХО, подпишется кто угодно...


S>Вне форм события мы не используем.


Я так и предположил...


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


Как всё запущено. ))


S>Мы используем вместо этого callback-интерфейс с одним методом. По нему легко отыскать подписчиков. (По сути event — это и есть интерфейс с одним методом, но анонимный.)


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


S>Используем ли мы подход DI? трудно сказать. Возможно и используем, не зная, что теперь это так называется.


Используете. На интерфейсах с одним методом это тоже имеет право на жизнь. Просто выглядит.. как-то по джавовски, что ле... В Reflector'е есть возможность посмотреть использование чего угодно и эта возможность хорошо работает не только на интерфейсах, легко можно отловить, кто именно подписывается на события. Сейчас Reflector платный, но цена всё-таки смешная. И есть плагин к студии. В общем, рекомендую. ИМХО, события — это удобная замена однометодным интерфейсам, чтобы не засорять информационное пространство проекта...


S>Но идеология приложения, раздробленного на миллион независимых запчастей, которые чудесным образом собираются в одно при запуске, меня не устраивает. В нем крайне сложно разобраться — кто с кем и зачем взаимодействует, чтобы потом добавлять новый функционал или менять старый.


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


S>Видимо, нужна очень подробная документация. (Но кто ее поддерживать в актуальном состоянии-то будет?) Наши приложения конечно не монолитны, но и не состоят из большого числа мелких "атомов", а скорее модулей.


Ну дык модули могут иметь зависимость от других модулей. Лучше всего для борьбы со сложностью — это когда зависимости однонаправленные и образуют иерархию. Тогда можно рассматривать выделенные "слои" приложения, придумывая и используя терминологию внутри слоя. Как раз, чтобы сложные унутре вещи обзывались простыми понятиями.

S>И эти модули явно регистрируются на старте приложения. Так что всегда можно средствами VS найти какой сервис будет активирован при запросе какого-либо интерфейса. Никаких регистраций в конфиг-файлах, только в коде.


Вполне покатит, когда не стоит задача динамического построения неизвестного заранее графа объектов.
Re[7]: Actor-based. Success story
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 29.06.12 06:09
Оценка: 64 (1)
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, Lazin, Вы писали:


V>>>

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

L>>Сразу выгребать оказывается надо, ты посмотри на него!

V>Не понял юмора. Я это написал рядом фактически сразу как обнаружились заинтересованные собеседники.


L>>Допустим у нас есть акторы Foo и Bar. Foo посчитал что-то и пытается записать это в очередь Bar, но она переполнена, потому что Bar не забирает оттуда сообщения, а не забирает он их оттуда потому что не может записать сообщение в очередь Foo, который ... В принципе цепочка может быть произвольной длины и даже может пересекать границы отдельных машин. Нет ничего невозможного


V>Ты не поверишь, но этот сценарий тоже был упомянут: http://www.rsdn.ru/forum/philosophy/4796651.1.aspx
Автор: vdimas
Дата: 29.06.12

V>

V>Оба ендпоинта насытили свои стеки TCP и оба ждали завершения синхронной отправки данных, а выгребать сокеты некому. Потому что шел синхронный обмен достаточно большими по размеру сообщениями (порядка полумегабайт). Вот тебе смешной "пространственный" дедлок. Асинхронность+событийная модель всё это лечит на раз.


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

Ну это один из вариантов, вариантов на самом деле тысячи С акторами очень даже возможен дедлок, в erlang-е возможен дедлок, если акторы могут ждать появления сообщений, то возможно ситуация, когда несколько акторов ждут сообщений друг от друга, но никто ничего не посылает. Это конечно проблема архитектуры, но и в обычном многопоточном программировании deadlock это как правило проблема архитектуры.

L>>Смысл ограничивать длину в том, чтобы клиент, который смог добавить сообщение в очередь, в том случае если ему не мешать, добавит туда еще одно и еще... Bounded очереди это простой и эффективный способ организовать back-pressure на producer-а.


V>Гы, ты описал простой и эффективный способ достичь банального дедлока и ничего больше. Это профанация любой асинхронности как она есть, ведь превращаешь асинхронный вызов в синхронный. Один тебе актуальный намек на эту тему: в протоколах VoIP в сигналинге бывают команды на уменьшение трафика и прочая дидагностика. Заметил как реагирует кач-во звука в Скайпе при изменении условий связи? Его протокол динамически меняет кодеки.


Актор, это очень легкий объект, размероп в пару сотен байт. Там не бывает сложного сигналинга как VoIP. Если код каждого актора будет знание о загруженности того актора, которому мы хотим отправить сообщение и мы должны будем писать код с учетом этой информации, то код будет либо очень и очень сложным, либо все просто будут тупо реализовывать ожидание в случае если актор загружен. В результате получится блокирующая очередь, реализованая через одно место.

V>>>========================

V>>>Например, если речь об асинхронном логировании при максимальном уровне логгирования. Тогда надо как-то изворачиваться, например, ренедрить лог-сообщения в буфер в памяти предварительно, т.е., чтобы кол-во операций IO не соответствовало 1:1 к кол-ву сообщений логирования, а записывать их пачками с неким коэф (брали порядка тысячи). Заметно снижает нагрузку на систему в целом. И вообще, вот этот способ передачи "пачками", даже когда речь о передаче сообщений м/у потоками — он самый эффективный, бо постоянное обращение к АПИ ОС или даже просто interlocked-операциям в одном месте снижает эффективность обращения к совсем другому АПИ ОС в другом месте. Например, за одну операцию на lock-free очереди разгребающий поток может получить все имеющиеся сообщения на данный момент (просто голову списка, обнулив shared-переменную через CAS), и потом разбирать пачку сообщений в цикле из локальной переменной-курсора без каких-либо тяжеловесных interlocked-операций. Если примененаа фильтрация этой пачки сообщений, то результат фильтрации чанка сообщений так же лучше прилепить в другую очередь целиком через одну interlocked операцию, вместо "ленивой" фильтрации и посылки резльтата в такую очередь по 1-му сообщению.

L>>То, что ты описал, зовется алгоритмом Нагла, ему сто лет в обед, но применение этого алгоритма для создания lock-free очереди, это что-то новое для меня


V>Нагль малость для другого, для увеличения полезной доли в трафике. Ведь, передавая по 1-му символу с учетом всех заголовков IP и низлежащего транспорта (ethernet или ISDN), мы получаем долю полезной нагрузки менее 1%. А здесь идет речь о кол-ве вызовов АПИ ОС. Мало того, что каждый вызов ОС, даже холостой, даже на простейшем примитиве ядерной синхронизации — семафоре, занимает сотни ns на моей почти топовой машине, дык еще после самого вызова происходит некий штраф на эффективность выполнения последующего юзерского кода (добавляющий порядка 100-200ns в общем), скорее всего из-за смены контекстов виртуальной памяти туда-сюда. Т.е. эти бесполезные ~1us на сообщение предлагалось размазать на много их. За ту же стоимость 1us можно отрендерить порядка нескольких мегабайт лога в памяти, если руки правильно растут.


Nope, он именно для того, чтобы кол. операций ввода/вывода не соотв. 1:1 количеству сообщений. Пока устройство ввода/вывода занято — накапливаем сообщения, как только оно освободилось — пушим все что накопили, либо столькло сколько возможно спушить за один раз, а если устройство не занято и пришло одно сообщение — пушим одно сообщение. Просто если речь идет об акторах, то этот батчинг сообщений должен делаться библиотекой а не кодом актора явным образом, это во превых, а во вторых, большую часть времени, акторы будут работать не с пиковой загрузкой, что естественно, поэтому сообщения будут отправляться и приниматься по одному. Тупой батчинг просто просадит в этом случае латентность и не даст заметного прироста производительности, а Нагл как раз позволяет в случае низкой нагрузки кидаться отдельными сообщениями, а в случае высокой — пачками сообщений, жертвуя латентностью.

V>Ну и ты не заметил еще важную вещь, никак к Наглю не относящуюся: ты можешь регулярно вызывать одни аспекты АПИ ОС из одного потока на многоядерной машине, скажем, вызывать в цикле простой опрос времени, а тормозить может где-то в совсем другом месте, то бишь минимальная стоимость ядерных вызовов ОС на совсем других потоках и ядрах процессора из-за тех первых вызовов возрастает. ИМХО, где-то что-то в процессе ядерных вызовов синхронизируется или постоянно обновляются данные, которые обязательно шарятся. Причем, на Линухах это проявляется ярче, чем в последних виндах (7-ка). Т.е. минимизировать кол-во ЛЮБЫХ вызовов АПИ ОС — благодарная задача само по себе. (Например, поэтому пришлось отказаться от потоковой библиотеки С++)

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

V>Ну и interlocked-операции тоже, хоть дешевле, но добавляют штрафов к эффективности кеша и сбрасывают конвейеры, поэтому максимум пропускной способности на межпотоковых lock-free очередях удалось выжать только в сценарии, когда одну очередь разгребает один поток и он "забирает" каждый раз на "свою сторону" все накопившиеся на текущий момент сообщения. А балансировка нагрузки в этом сценарии наиболее эффективна по модели master-slave потоков, где мастер-поток единолично выгребает ту самую очередь и посылает другим рабочим потокам сообщения только в случае, если сам плохо справляется, то бишь когда размеры забираемых каждый раз пачек возрастают. Ес-но для нормальной работы всей системы никакой тупой bounding не пойдет. Курить ПИД-управление. Реагировать, когда очередь уже насытилась, поздно — почки уже отлетели. Надо следить за производными и интегралом, то бишь средней нагрузкой и динамикой на её фоне, а обратная пропорциональная связь задает коэф. жесткости управления... Кстате, как раз на ПИД делал де-джиттер для миксера VoIP. Много потоков шлют пакеты потоку-миксеру, который регулирует длину линии задержки в зависимости от динамики условий. Для диспатчинга сообщений делал чуть более простое управление, только ИП, без Д, но там нагрузка многократно меньше, так что хватало простого сглаживания средней нагрузки и обратной пропорциональной связи для принятия решений, сколько дополнительных потоков брать из пула.

Тоесть ты предлагаешь использовать ПИД регулятор для балансировки нагрузки между процессорами? В таком случае, ты должен знать, что ПИД регулятор обычно включается в контур обратной связи, то бишь ты должен уметь влиять на producer-а сообщений, а тупоой bounding это как-раз и есть такая обратная связь, только вместо ПИД-регулятора у нас будет нелинейность — насыщение Вообще, конечно интересный ход мысли, никогда не думал в таком ключе о системе producer/consumer
Re[8]: Actor-based. Success story
От: WolfHound  
Дата: 29.06.12 06:37
Оценка:
Здравствуйте, Mamut, Вы писали:

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

Эффект проявляется на 10% процентах от предельной нагрузки.
Достаточно одного кратковременного всплеска.
И приплыли.

M>>>а Singularity с каналами не видно просто тупо нигде.

WH>>Пошла демагогия.
M>Пошли факты
Нет. Демагогия.
Ибо сперва добейся не аргумент.
И тут это в двойне не аргумент.
Ибо если бы мелкософт начал продвигать сингулярити то сейчас бы использовали ее, а не ерланг.

M>Уже и фантазии про ровные места пошли

Кратковременный всплеск при 10%ной нагрузки это ровное место.

M>Это намек на то, что пропагандируемые тобой подходы на практике днем с огнем не.

http://blogs.jetbrains.com/dotnet/2012/06/jetbrains-and-nemerle/
"Core developers behind a project called Nemerle" это я, Влад и Хардкейс.
Так что через пару тройку лет мы еще посмотрим, что будет более распространено. N2 или ерланг.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: Actor-based. Success story
От: Mamut Швеция http://dmitriid.com
Дата: 29.06.12 06:48
Оценка:
M>>>>а Singularity с каналами не видно просто тупо нигде.
WH>>>Пошла демагогия.
M>>Пошли факты
WH>Нет. Демагогия.
WH>Ибо сперва добейся не аргумент.
WH>И тут это в двойне не аргумент.
WH>Ибо если бы мелкософт начал продвигать сингулярити то сейчас бы использовали ее, а не ерланг.

Бгггг. И этот человек мне рассказывает про демагогию. Ну-ну

M>>Уже и фантазии про ровные места пошли

WH>Кратковременный всплеск при 10%ной нагрузки это ровное место.

Нет, не ровное.


M>>Это намек на то, что пропагандируемые тобой подходы на практике днем с огнем не.

WH>http://blogs.jetbrains.com/dotnet/2012/06/jetbrains-and-nemerle/
WH>"Core developers behind a project called Nemerle" это я, Влад и Хардкейс.
WH>Так что через пару тройку лет мы еще посмотрим, что будет более распространено. N2 или ерланг.

Вот через пару-тройку лет и приходи.


dmitriid.comGitHubLinkedIn
Re[10]: Actor-based. Success story
От: WolfHound  
Дата: 29.06.12 08:24
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Бгггг. И этот человек мне рассказывает про демагогию. Ну-ну

Это не демагогия.
Это факты.
Только объявление о том, что JetBrains берет немерле значительно подняло интерес к языку.
А тут мы сравниваем ерланг который поддерживает ериксон и сингулярити которую не поддерживает никто.

WH>>Кратковременный всплеск при 10%ной нагрузки это ровное место.

M>Нет, не ровное.
Абсолютно ровное.
Ибо кратковременный всплеск это штатное явление.
Кратковременные всплески должны рассасываться сами даже на 90%ной средней нагрузке.
А тут на 10%ной все падает.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: Actor-based. Success story
От: Mamut Швеция http://dmitriid.com
Дата: 29.06.12 08:31
Оценка: :)
M>>Бгггг. И этот человек мне рассказывает про демагогию. Ну-ну
WH>Это не демагогия.
WH>Это факты.
WH>Только объявление о том, что JetBrains берет немерле значительно подняло интерес к языку.
WH>А тут мы сравниваем ерланг который поддерживает ериксон и сингулярити которую не поддерживает никто.

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

Ах, да, что у JetBrains есть промышленного масштаба кроме IDE?


dmitriid.comGitHubLinkedIn
Re[8]: Actor-based. Success story
От: WolfHound  
Дата: 29.06.12 08:51
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Чтобы оно сваливалось в O(N^2), надо чтобы адрес каждый раз получался минимум за O(N) и сообщение доставлялось (т.е. ресолвился адрес) тоже за O(N), где N — кол-во акторов... а так-то обе операции выполнимы за O(1).

Я несколько раз явно сказал, что selective receive приводит к O(N^2) где N количество сообщений в очереди актора.

V>Цимус в том, что нет никакого смысла посылать сообщение конкретному каналу в общем случае. Даже если в Сингулярити это на уровне языка видится именно так, реально это может происходить не так. Асинхронная отсылка может идти в общую очередь с привязанным идентификатором канала, а эта очередь затем может разгребаться на пуле потоков.

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

V>Почему так? Предлагаю порассуждать на предмет как времени жизни каналов,

Никаких проблем с этим нет. Просто убиваем канал, когда подохли оба конца и все.

V>так и на предмет того, что канал вовсе не обязан иметь выделенный физический поток-обработчик сообщений.

Это тоже ни разу не проблема.

V>Асинхронная модель поверх событийной (то бишь на пуле потоков) хороша тем, что не требует обязательного физического потока на каждый актор. Хотя, никто не запрещает акторам создавать такие потоки для своих внутренних нужд. Просто я не представляю работу на каналах обработчиков хотя бы для тысячи подключений, если к каждому подключению привязывается минимум 5 акторов для логики всего приложения...

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

V>И на последок как пример — асинхронный ввод/вывод в виндах в сокеты.

1)Очень примитивный пример. Там selective receive нет. Так что и O(N^2) не появляется.
2)Весь этот код упирается в пропускную способность сети. Так что тут вообще говорить не о чем.
Ты блин как мамут. Он тоже доказывал что ерланг работает быстро на основе теста который только и делал что IO.

V>Скорее намек на то, что в последнее время ты больше обсуждаешь несуществующие в реальном воплощении и необкатанные на практике вещи.

Я просто могу анализировать различные решения.
И поэтому вижу, какие у них есть проблемы.
А ты даже не можешь понять, откуда у selective receive появляется O(N^2). Это даже мамут понимает. Хотя и пытается всех убедить, что это ерунда.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: Actor-based. Success story
От: WolfHound  
Дата: 29.06.12 09:20
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Ну и чем это отличается от обычной событийной модели с т.з. конкретного актора? Если низлежащая система, например, гарантирует, что конкретному актору приложения будут приходить ровно по 1-му, и следующее не придет до тех пор, пока не вернется предыдущий вызов...

Так это и есть логический поток.
Просто разбор очереди сообщений написан не явно.

V>

V>Например, акторы могут использовать конвейер обработки сообщений. Это означает, что в процессе обработки сообщения M1 актор может варьировать поведение, которое будет использоваться для обработки следующего сообщения. В частности, это означает, что он может начать обработку ещё одного сообщения M2 до завершения обработки M1. На том основании, что актору предоставлено право использования конвейера обработки сообщений, ещё не означает, что он этот конвейер обязан использовать. Будет ли сообщение конвейеризовано или нет — относится к задачам технического компромисса.

Чем дальше, тем фееричнее.
Если у нас обработка сообщений независима, то зачем их вообще обрабатывать одним процессом?
Где смысл?

V>Очень подходит к системам, где слово "протокол" не пустой звук. Самое оно.

Этим системам неизмеримо лучше подходит модель сингулярити.
Там протоколы описаны явно. И проверяются аж компилятором во время компиляции.

V>ОМГ... Издеваешься? Рассказываю медленно... Чтобы соблюдать SRP зачастую приходится применять процесс IoC, который транзитивно ведет к последующему обязательному DI.

Не приходится. Все дальнейшие рассуждения идут в мусор.

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

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

V>Пока что ты увидел вообще одно-единственное дерево — это собственное представление об асинхронности. Ты не застал DOS и явное управление прерываниями? Как же так оно раньше работало асинхронно вообще без выделенных потоков?

Ох. Совершенно не можешь отделить модель от деталей реализации.
Ну совсем.

V>Чтобы ему решать, у него должна быть возможность выбирать.

В моей модели она есть.

V>Нет, я показал, что O(N) для selective receive в случае ожидания одного сообщения — это бред сивой кобылы. Хотя, если КАЖДОЕ сообщение доставать по selective receive, то да-а-а... то нафига тебе асинхронность вообще? При чем тут тогда акторы?

При запросе selective receive в гугле его проблемы описаны во второй из более чем 30 миллионов ссылок.
Подумай об этом.

V>Да я вижу, что асинхронность вообще для тебя загадка... А что я делаю, если у меня есть данные, а сокет еще не готов их принять? Неужели загадка? Некоторые так и ждут бесконечно на сокете, что порой провоцирует интересный пространственный дедлок двух компьютеров (!!!), получателя и отправителя. Лечил я и такое в синхронном программировании. Оба ендпоинта насытили свои стеки TCP и оба ждали завершения синхронной отправки данных, а выгребать сокеты некому. Потому что шел синхронный обмен достаточно большими по размеру сообщениями (порядка полумегабайт). Вот тебе смешной "пространственный" дедлок. Асинхронность+событийная модель всё это лечит на раз.

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

V>Нужны-нужны. Спроси у АВК, он тебе растолкует, если не понимаешь.

Я с ним работал. Он очень любит архитектурить на ровном месте.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Actor-based. Success story
От: WolfHound  
Дата: 29.06.12 09:28
Оценка:
Здравствуйте, Кодёнок, Вы писали:

Кё>Я имел ввиду по сравнению с race condition при многопоточности. В актерах само собой их не бывает.

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

Чтобы избавить себя от race condition нужно использовать модель каналов из сингулярити.
Там чтобы нарваться на race condition нужно явно в коде, написать ожидание на более чем одном канале.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: Actor-based. Success story
От: vdimas Россия  
Дата: 29.06.12 11:31
Оценка:
Здравствуйте, Lazin, Вы писали:

L>С акторами очень даже возможен дедлок, в erlang-е возможен дедлок, если акторы могут ждать появления сообщений, то возможно ситуация, когда несколько акторов ждут сообщений друг от друга, но никто ничего не посылает.


Если они при этом способны обрабатывать другие сообщения, то нет никакого дедлока, это стандартный режим ожидания событий. Дедлок — это когда они блокируют друг-другу какую-либо возможность работы.

L>Это конечно проблема архитектуры,


Я пока не понял, в чем состоит описанная тобой проблема?

L>но и в обычном многопоточном программировании deadlock это как правило проблема архитектуры.


Дедлок — это проблема сугубо синхронных операций в многопоточном окружении. Несколько синхронных алгоритмов взаимно завладели ресурсами, которые требуются для продолжения их потоков (синхронных алгоритмов), вот тебе и дедлок. У меня не хватает фантазии понять, как можно получить дедлок в асинхронной среде акторов. Можно на пальцах??? Ес-но считаем, что акторы не шарят м/у собой примитивы синхронизации, иначе зачем бы они (акторы) были нужны...


V>>Гы, ты описал простой и эффективный способ достичь банального дедлока и ничего больше. Это профанация любой асинхронности как она есть, ведь превращаешь асинхронный вызов в синхронный. Один тебе актуальный намек на эту тему: в протоколах VoIP в сигналинге бывают команды на уменьшение трафика и прочая дидагностика. Заметил как реагирует кач-во звука в Скайпе при изменении условий связи? Его протокол динамически меняет кодеки.


L>Актор, это очень легкий объект, размероп в пару сотен байт. Там не бывает сложного сигналинга как VoIP. Если код каждого актора будет знание о загруженности того актора, которому мы хотим отправить сообщение и мы должны будем писать код с учетом этой информации, то код будет либо очень и очень сложным, либо все просто будут тупо реализовывать ожидание в случае если актор загружен. В результате получится блокирующая очередь, реализованая через одно место.


Актор — это подход к обмену сообщениями и ничего более. При чем тут сотня байт? Речь вообще шла о диспатчинге сообщений, то бишь не об акторах... сигналинг был лишь как пример.

Т.е. нагрузку можно балансировать:
1. протоколом связи самих аторов (один другому шлет сообщения "уменьшить трафик");
2. балансировкой нагрузки — низлежащий слой может понижать приоритет актора-генератора сообщений или делать еще что-либо, чтобы давать ему меньше квантов процессора на генерацию трафика и давать больше тому, у кого больше накопилось сообщений.


V>>Нагль малость для другого, для увеличения полезной доли в трафике. Ведь, передавая по 1-му символу с учетом всех заголовков IP и низлежащего транспорта (ethernet или ISDN), мы получаем долю полезной нагрузки менее 1%. А здесь идет речь о кол-ве вызовов АПИ ОС. Мало того, что каждый вызов ОС, даже холостой, даже на простейшем примитиве ядерной синхронизации — семафоре, занимает сотни ns на моей почти топовой машине, дык еще после самого вызова происходит некий штраф на эффективность выполнения последующего юзерского кода (добавляющий порядка 100-200ns в общем), скорее всего из-за смены контекстов виртуальной памяти туда-сюда. Т.е. эти бесполезные ~1us на сообщение предлагалось размазать на много их. За ту же стоимость 1us можно отрендерить порядка нескольких мегабайт лога в памяти, если руки правильно растут.


L>Nope, он именно для того, чтобы кол. операций ввода/вывода не соотв. 1:1 количеству сообщений. Пока устройство ввода/вывода занято — накапливаем сообщения, как только оно освободилось — пушим все что накопили, либо столькло сколько возможно спушить за один раз, а если устройство не занято и пришло одно сообщение — пушим одно сообщение.


Гы, непонимание. Нагль работает не так. В алгоритме Нагля задается некий таймаут на ожидание, обычно по-умолчанию это 200ms. Если кол-во накопленных в буфере байт меньше размера пакета, который собрался сформировать стек TCP (например, поверх ethernet это ~1400 байт), то ничего в сокет не отправляется в течении таймаута, будут ожидаться еще данные пока не пройдет таймаут или пока не хватит данных на полный пакет. Т.е. Нагль — это не объединение накопленных данных, а их ожидание. Поэтому для сигналинга Нагль обязательно отключают, ведь roundtrip при включенном нагле составляет минимум 400ms, почти пол-секунды. А при отключенном — данные отправляются мгновенно по мере готовности сокета отправлять данные.

Т.е. ошибка твоя в том, что объединение данных (записываемых в сокет пакетов) в пачки ты посчитал алгоритмом Нагля. И еще меня попытался ткнуть нгосом дважды. ))

Для TCP исходщяие данные объединяются ВСЕГДА, вне зависимости от того, включил ты для сокета опцию NO_DELAY (эта опция управляет Наглем) или нет. Они не объединяются только в том случае, если сокет отправляет пакеты быстрее, чем ты способен ему их формировать. Но это как бы и так понятно...


L>Просто если речь идет об акторах, то этот батчинг сообщений должен делаться библиотекой а не кодом актора явным образом,


Ес-но, межпотоковые очереди для диспатчинга сообщений — это сугубо инфраструктура. Но случай с логами — это вполне прикладной случай.

L>большую часть времени, акторы будут работать не с пиковой загрузкой, что естественно, поэтому сообщения будут отправляться и приниматься по одному. Тупой батчинг просто просадит в этом случае латентность и не даст заметного прироста производительности, а Нагл как раз позволяет в случае низкой нагрузки кидаться отдельными сообщениями, а в случае высокой — пачками сообщений, жертвуя латентностью.


1. Нагля ты не понимаешь;
2. Принцип забора всей пачки за раз тоже не понимаешь. Эта операция ничуть не дороже забора одного сообщения, что в случае обычных мьютексов, что на lock-free очередях и CAS. Потом-то эти сообщения будут точно в таком же порядке отправлены потребителю, но с один бонусом — на каждое это сообщение уже не будет вызовов вокруг примитивов синхронизации и не будет interlocked-операций.


L>Минимизация количества ядерных вызовов это всегда благородная задача, даже в однопоточных приложениях Вообще, мысль от акоторов уже достаточно далеко уже ушла, не находишь?


Ну нас же попросили рассказать о реальных историях, а не просто органом поболтать, не находишь? Просто асинхронность добавляет дерганье всяких таких примитивов синхронизации или interlocked-операций на каждый вызов, в то время как синхронный код дергает эти же вещи гораздо реже. Поэтому считаю всё упомянутое обязательным держать в голове. Поэтому-то и предлагаю делать акторами объекты лишь самого высокого уровня и только те, которые действительно нуждаются в асинхроном вводе/выводе прикладных событий.

L>Тоесть ты предлагаешь использовать ПИД регулятор для балансировки нагрузки между процессорами?


Между акторами, то бишь как потоками, так и фиберами так и приоритетом выдачи сообщений.

L>В таком случае, ты должен знать, что ПИД регулятор обычно включается в контур обратной связи,


Серьезно? )))

Исходные данные для обратной связи — это показатели диагностики, например, длина очереди сообщений к каждому актору. А регулирующие механизмы уже перечислял.

L>то бишь ты должен уметь влиять на producer-а сообщений, а тупоой bounding это как-раз и есть такая обратная связь, только вместо ПИД-регулятора у нас будет нелинейность — насыщение Вообще, конечно интересный ход мысли, никогда не думал в таком ключе о системе producer/consumer


Ну вот пробовал на де-джиттере для VoIP, сразу намного лучше чем на деджиттере с тупой пропорциональной обратной связью. Ведь интегральная составляющая в ПИД вычисляет "общий фон" то бишь общую латентность, а в случае тупого пропорционального управления этой информации нет. Далее, дифференциальная составляющая показывает текущую динамику. Т.е. можно начинать реагировать не тогда, когда очередь забита входными пакетами и их остается только дропать (для случая VoIP), а заранее. Очень удобно пользовать такую информацию для обратных связей с задержками.
Re[9]: Actor-based. Success story
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 29.06.12 16:55
Оценка: +1
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, Lazin, Вы писали:


V>Если они при этом способны обрабатывать другие сообщения, то нет никакого дедлока, это стандартный режим ожидания событий. Дедлок — это когда они блокируют друг-другу какую-либо возможность работы.

Нет есть, попробуй переложить на асинхронные сообщения проблему обедающих философов и убедись сам

V>Гы, непонимание. Нагль работает не так. В алгоритме Нагля задается некий таймаут на ожидание, обычно по-умолчанию это 200ms. Если кол-во накопленных в буфере байт меньше размера пакета, который собрался сформировать стек TCP (например, поверх ethernet это ~1400 байт), то ничего в сокет не отправляется в течении таймаута, будут ожидаться еще данные пока не пройдет таймаут или пока не хватит данных на полный пакет. Т.е. Нагль — это не объединение накопленных данных, а их ожидание. Поэтому для сигналинга Нагль обязательно отключают, ведь roundtrip при включенном нагле составляет минимум 400ms, почти пол-секунды. А при отключенном — данные отправляются мгновенно по мере готовности сокета отправлять данные.


V>Т.е. ошибка твоя в том, что объединение данных (записываемых в сокет пакетов) в пачки ты посчитал алгоритмом Нагля. И еще меня попытался ткнуть нгосом дважды. ))


V>Для TCP исходщяие данные объединяются ВСЕГДА, вне зависимости от того, включил ты для сокета опцию NO_DELAY (эта опция управляет Наглем) или нет. Они не объединяются только в том случае, если сокет отправляет пакеты быстрее, чем ты способен ему их формировать. Но это как бы и так понятно...

Странно, но сам Джон Нагл не знал что его алгоритм так работает:

The solution is to inhibit the sending of new TCP segments when
new outgoing data arrives from the user if any previously
transmitted data on the connection remains unacknowledged. This
inhibition is to be unconditional; no timers, tests for size of
data received, or other conditions are required.



V>1. Нагля ты не понимаешь;

V>2. Принцип забора всей пачки за раз тоже не понимаешь. Эта операция ничуть не дороже забора одного сообщения, что в случае обычных мьютексов, что на lock-free очередях и CAS. Потом-то эти сообщения будут точно в таком же порядке отправлены потребителю, но с один бонусом — на каждое это сообщение уже не будет вызовов вокруг примитивов синхронизации и не будет interlocked-операций.
А ты не понимаешь bandwidth/latency tradeoff и capacity planning
Re[5]: Actor-based. Success story
От: vdimas Россия  
Дата: 29.06.12 17:43
Оценка: -1 :)
Здравствуйте, WolfHound, Вы писали:

WH>Да даже сообщения одного актора могут прийти не в том порядке, в котором их посылали. И это тоже race condition.


Это регулируется взаимной политикой доставки. "Сообщения могут придти не в том порядке" — это определение из Вики, которое утверждает, что не накладывает на модель акторов каких-либо ограничений. Не надо делать далекоидущие выводы, никто не запрещает разнообразить политику доствки сообщений моделью последовательных каналов. Абсолютно ничего не поменяется с т.з. определения акторов, если со стороны отсылающего всё будет происходить асинхронно.


WH>Чтобы избавить себя от race condition нужно использовать модель каналов из сингулярити.


Не поможет. Абсолютно ничего не изменится в случае двух независимых каналов м/у одними и теми же агентами. И да, сам канал можно рассматривать как частный случай: выделенную пару вспомогательных агентов на его концах, упорядочивающих сообщения.


WH>Там чтобы нарваться на race condition нужно явно в коде, написать ожидание на более чем одном канале.


Если не хочется получить проблемы с надежностью, то ожидать надо на ВСЕХ каналах, на которые могут приходить сообщения. Иначе это шапкозакидательство и порчий детсад из разряда "всё будет ОК, пока мы подождем только на этом канале"...
Re[10]: Actor-based. Success story
От: vdimas Россия  
Дата: 29.06.12 19:20
Оценка:
Здравствуйте, Lazin, Вы писали:

V>>Если они при этом способны обрабатывать другие сообщения, то нет никакого дедлока, это стандартный режим ожидания событий. Дедлок — это когда они блокируют друг-другу какую-либо возможность работы.

L>Нет есть, попробуй переложить на асинхронные сообщения проблему обедающих философов и убедись сам

Ты мне давай мне лучше давай конкретную задачу, которая приводит к дедлоку в синхронном режиме и я тебе покажу, почему можно избежать дедлока в асинхронном. Ну кроме того предложенного тобой случая, когда вся доступная память будет забита данными, которые компьютер не успевает обрабатывать. Только это не дедлок называется, а чуть по-другому. )))

L>Странно, но сам Джон Нагл не знал что его алгоритм так работает:

L>

The solution is to inhibit the sending of new TCP segments when
L>new outgoing data arrives from the user if any previously
L>transmitted data on the connection remains unacknowledged. This
L>inhibition is to be unconditional; no timers, tests for size of
L>data received, or other conditions are required.

L>

Ну и? Это ты с одной стороны указал. А как приходит подтверждение с обратной стороны? А что есть опция fasttimo? Поищи по этому слову, в некоторых операционках этой штукой можно управлять. В сетке с быстрым roundtrip приведенный тобой отрывок никак не решает проблемы маленьких пакетов, се ля ви, её решает отложенный на 200ms (по умолчанию) ACK. Так что даже в самой быстрой сетке, при включенном Нагле, если слать короткие пакеты, то ты получишь порядка ~2.5 синхронных обмена пакетами в секунду. Если не веришь — какие проблемы поэкспериментировать и убедиться самому? При отключенном Нагле и прямых руках можно получить десятки тысяч синхронных обменов такими же маленькими пакетами в секунду.

В любом случае, даже в твоей "версии алгоритма Нагля" это и близко не то, что я предлагал делать для межпотоковых очередей. Даже если брать описание работы только одной стороны, то в алгоритме Нагля участвует размер кадра и размер окна (читать RFC-896 целиком) если данных на кадр хватает, то они отсылаются немедленно до тех пор, пока размер TCP-окна не больше текущего максимального.

Т.е. ты как бэ не понимаешь собеседника (факт налицо) и я не уверен, стоит ли дальше распинаться...
Re[9]: Actor-based. Success story
От: vdimas Россия  
Дата: 29.06.12 19:25
Оценка:
Здравствуйте, WolfHound, Вы писали:

M>>Это намек на то, что пропагандируемые тобой подходы на практике днем с огнем не.

WH>http://blogs.jetbrains.com/dotnet/2012/06/jetbrains-and-nemerle/
WH>"Core developers behind a project called Nemerle" это я, Влад и Хардкейс.

Хрена себе новость! Достойная отдельного топика. Они будут инвестировать разработку N2?

Чисто любопытство — только деньгами (переводя разработку N2 на фулл-тайм) или ресурсами тоже?
Re[10]: Actor-based. Success story
От: Jack128  
Дата: 29.06.12 19:38
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, WolfHound, Вы писали:


M>>>Это намек на то, что пропагандируемые тобой подходы на практике днем с огнем не.

WH>>http://blogs.jetbrains.com/dotnet/2012/06/jetbrains-and-nemerle/
WH>>"Core developers behind a project called Nemerle" это я, Влад и Хардкейс.

V>Хрена себе новость! Достойная отдельного топика. Они будут инвестировать разработку N2?


Ну как бе в соотвествующем форуме обсуждают: http://rsdn.ru/forum/nemerle/4789575.1.aspx
Автор: VladD2
Дата: 22.06.12
Re[9]: Actor-based. Success story
От: vdimas Россия  
Дата: 29.06.12 21:22
Оценка:
Здравствуйте, WolfHound, Вы писали:

V>>Чтобы оно сваливалось в O(N^2), надо чтобы адрес каждый раз получался минимум за O(N) и сообщение доставлялось (т.е. ресолвился адрес) тоже за O(N), где N — кол-во акторов... а так-то обе операции выполнимы за O(1).

WH>Я несколько раз явно сказал, что selective receive приводит к O(N^2) где N количество сообщений в очереди актора.

Но ты не пояснил, зачем доставать КАЖДОЕ сообщение по selective receive? Это какой-то специальный радиус кривизны рук или что? (Я уже высказывал своё мнение относительно попыток "пристроить" синхронный код в событийную модель. )

V>>Цимус в том, что нет никакого смысла посылать сообщение конкретному каналу в общем случае. Даже если в Сингулярити это на уровне языка видится именно так, реально это может происходить не так. Асинхронная отсылка может идти в общую очередь с привязанным идентификатором канала, а эта очередь затем может разгребаться на пуле потоков.

WH>Аааааааааа!
WH>Мужики всеми силами придумывали модель, которая не имеет бутылочного горлышка, а ты его искусственно создал.

Мде, приплызд... Разве перевод хендла файла в конкретный драйвер внутри дороже O(1)? Вернись выше, прочитай еще раз, что ты там утверждал. Ты фактически утверждаешь, что есть прицнипиальная разница м/у channel.send(data) и send(channel, data). Это уже какое-то нубство, сорри.

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

V>>Почему так? Предлагаю порассуждать на предмет как времени жизни каналов,

WH>Никаких проблем с этим нет. Просто убиваем канал, когда подохли оба конца и все.

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


V>>так и на предмет того, что канал вовсе не обязан иметь выделенный физический поток-обработчик сообщений.

WH>Это тоже ни разу не проблема.

Разве? Ну тогда прямо сейчас стоит остановиться и внимательно посмотреть — а точно ли идет спор о разных вещах, или кто-то не умеет формулировать свои мысли? А то как бы не было опять смешно...

Потому как балансировка нагрузки внутри ОС все-равно происходит синхронно, се ля ви. Очередь ожидания на примитивах синхронизации — она общая на все потоки/процессы и обрабатывается внутри осей синхронно. Т.е. даже если ты в памяти организуешь независимые очереди, то, ожидая ресурсы процессора на примитивах синхронизации, у тебя все-равно происходит объединение всех этих очередей ровно в одну очередь на прием к шедуллеру ОС. И здесь нет никакого бутылочного горлышка, ес-но, если диспатчить все поступающие события подряд, а не искать каждый раз "специальное". В случае приоритетных очередей и простого диспатчинга одного сообщения будет порядка K*O(x), где O(x) — стоимость операции шедуллинга в отсутствии приоритетов.

Просто я точно такой же механизм, который используется внутри оси, сделал на юзерском уровне, чтобы сократить общее кол-во ядерных примитивов синхронизации и нейтивных потоков (чем больше нейтивных потоков и примитивов синхронизации, на которых они ожидают, тем тормознутее всё работает). А так-то происходящее внутри ничем не отличалось от автобалансировки нагрузки м/у приложениями внутри ОС... А происходящее снаружи — от асинхронного ввода/вывода на сокетах (если так понятнее). Потому что модель акторов — это и есть модель ОС и независимых приложений, работающих в этой ОС и общающихся по неблокирующим линиям связи.
Re[10]: Actor-based. Success story
От: vdimas Россия  
Дата: 29.06.12 22:24
Оценка:
Здравствуйте, WolfHound, Вы писали:


V>>

V>>Например, акторы могут использовать конвейер обработки сообщений. Это означает, что в процессе обработки сообщения M1 актор может варьировать поведение, которое будет использоваться для обработки следующего сообщения. В частности, это означает, что он может начать обработку ещё одного сообщения M2 до завершения обработки M1. На том основании, что актору предоставлено право использования конвейера обработки сообщений, ещё не означает, что он этот конвейер обязан использовать. Будет ли сообщение конвейеризовано или нет — относится к задачам технического компромисса.

WH>Чем дальше, тем фееричнее.

Из Вики вырезка.
Я же говорю, ты под термином акторов понимаешь что-то сугубо своё... Я еще тольком не разобрался, что именно ты имеешь ввиду, но уже близок. Но это не акторы, а некая система с ограничениями на их основе.


WH>Если у нас обработка сообщений независима, то зачем их вообще обрабатывать одним процессом?

WH>Где смысл?

Если состояние одно общее, то вот и смысл. Простейший пример — некий прокси м/у двумя ендпоинтами или аналогичный по функциональности адаптер кодеков/протоколов и т.д. до бесконечности. Изменения состояния одного из каналов должны влиять на состояние другого (это же очевидно). И это я тебе буквально простейший пример привел, ХЗ как ты сам не додумался.

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

V>>Очень подходит к системам, где слово "протокол" не пустой звук. Самое оно.

WH>Этим системам неизмеримо лучше подходит модель сингулярити.
WH>Там протоколы описаны явно. И проверяются аж компилятором во время компиляции.

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


V>>ОМГ... Издеваешься? Рассказываю медленно... Чтобы соблюдать SRP зачастую приходится применять процесс IoC, который транзитивно ведет к последующему обязательному DI.

WH>Не приходится.

Я так понимаю, что привести подтверждающий пример проблемы составить не должно?


WH>Все дальнейшие рассуждения идут в мусор.


Это у тебя в голове мусор, рассуждаешь о том, чего не понимаешь. Нет изолированности — нет SRP, точка. ЛЮБАЯ лишняя зависимость требует поддержки в фунцкиональности. Если не требует — значит зависимости нет. Избавление от зависимостей идет через IoC и пока больше не придумали альтернативного способа даже в других парадигмах (не только ООП). Например, в ФП трюк IoC — основной и фактически единственный в проектировании после обычной процедурной декомпозиции сложности. Использование ФВП идет исключительно в сценариях IoC. Ты этим трюком пользуешь постоянно/обязательно если пишешь в ФП проекты сложнее сотен-единиц тысяч строк. Но т.к. терминологией и понятиями из области проектирования ПО не владеешь, упорствуешь на отсебятине.
Re[11]: Actor-based. Success story
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 30.06.12 06:09
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Ну и? Это ты с одной стороны указал. А как приходит подтверждение с обратной стороны? А что есть опция fasttimo? Поищи по этому слову, в некоторых операционках этой штукой можно управлять. В сетке с быстрым roundtrip приведенный тобой отрывок никак не решает проблемы маленьких пакетов, се ля ви, её решает отложенный на 200ms (по умолчанию) ACK. Так что даже в самой быстрой сетке, при включенном Нагле, если слать короткие пакеты, то ты получишь порядка ~2.5 синхронных обмена пакетами в секунду. Если не веришь — какие проблемы поэкспериментировать и убедиться самому? При отключенном Нагле и прямых руках можно получить десятки тысяч синхронных обменов такими же маленькими пакетами в секунду.

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

V>В любом случае, даже в твоей "версии алгоритма Нагля" это и близко не то, что я предлагал делать для межпотоковых очередей. Даже если брать описание работы только одной стороны, то в алгоритме Нагля участвует размер кадра и размер окна (читать RFC-896 целиком) если данных на кадр хватает, то они отсылаются немедленно до тех пор, пока размер TCP-окна не больше текущего максимального.

То, что ты предлагаешь, совсем для акторов не подходит, по причине того, что сообщения, в случае низкой нагрузки, буферизовать вовсе не нужно, задерживать их тоже нельзя, поэтому, в этом случае, батчинг должен отключаться и акторы должны тянуть сообщения из очередей по одному. Nagle это обеспечивает, а описанная тобой реализация — нет, она выльется в рост латентности и снижение общей производительности в тех случаях, когда очереди заполняются медленно.
Дальше — больше, если в нашей системе акторов есть куча переполненных очередей, то это может означать только одно — работу в режиме out of capacity. Тут нужно увеличивать capacity, либо увеличивать пропускную способность системы за счет распараллеливания тяжелых этапов обработки или использования более быстрых алгоритмов, а не уменьшать издержки на CAS-ы при чтении из очередей. Вот такой батчинг как ты описал, подходит для записи в файл, например.

V>Т.е. ты как бэ не понимаешь собеседника (факт налицо) и я не уверен, стоит ли дальше распинаться...

Если тебя не понимают, то это твои проблемы, если не можешь внятно выразить свои мысли, так, чтобы тебя поняли, то может действительно не стоит
Re[11]: Actor-based. Success story
От: WolfHound  
Дата: 30.06.12 07:25
Оценка: +1
Здравствуйте, vdimas, Вы писали:

V>Из Вики вырезка.

Да мне плевать на каком заборе это написано.

WH>>Если у нас обработка сообщений независима, то зачем их вообще обрабатывать одним процессом?

WH>>Где смысл?
V>Если состояние одно общее, то вот и смысл.
Ты что, правда не понимаешь разницы между "общим состоянием" и "независимой обработкой"?

V>Простейший пример — некий прокси м/у двумя ендпоинтами или аналогичный по функциональности адаптер кодеков/протоколов и т.д. до бесконечности. Изменения состояния одного из каналов должны влиять на состояние другого (это же очевидно). И это я тебе буквально простейший пример привел, ХЗ как ты сам не додумался.

Ох. Тут появляется состояние.
Два сообщения не могут одновременно менять состояние. Иначе состояние будет испорчено.
Значит, тебе придется упорядочить обработку этих сообщений.
И получили поток.

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

V>Это на уровне одного канала, считай что ничего. В реальных приложениях смысла в одном процессе с одним каналом очень немного. Это только где-то на самых "концах" системы, типа асинхронного логгера. Даже сложно придумать задачу, где бы был достаточен один канал на одно приложение, кроме этого логгера... не подскажешь?

Никто не мешает проверять сколько угодно каналов одновременно в одном процессе.
Тривиальная задача.

V>>>ОМГ... Издеваешься? Рассказываю медленно... Чтобы соблюдать SRP зачастую приходится применять процесс IoC, который транзитивно ведет к последующему обязательному DI.

WH>>Не приходится.
V>Я так понимаю, что привести подтверждающий пример проблемы составить не должно?
Это ты говоришь, что без DI-контейнера SRP соблюсти нельзя.
Вот ты и доказывай.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: Actor-based. Success story
От: WolfHound  
Дата: 30.06.12 07:38
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Но ты не пояснил, зачем доставать КАЖДОЕ сообщение по selective receive? Это какой-то специальный радиус кривизны рук или что? (Я уже высказывал своё мнение относительно попыток "пристроить" синхронный код в событийную модель. )

Если у тебя на почтовом ящике появляется selective receive то тебе придется доставать из него все сообщения через selective receive.
Если же у тебя некоторые сообщения проскакивают мимо, то фактически мы имеем отдельный канал доставки этих сообщений.
О чем я тебе тут и твержу.

V>Мде, приплызд... Разве перевод хендла файла в конкретный драйвер внутри дороже O(1)? Вернись выше, прочитай еще раз, что ты там утверждал. Ты фактически утверждаешь, что есть прицнипиальная разница м/у channel.send(data) и send(channel, data). Это уже какое-то нубство, сорри.

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

V>>Цимус в том, что нет никакого смысла посылать сообщение конкретному каналу в общем случае. Даже если в Сингулярити это на уровне языка видится именно так, реально это может происходить не так. Асинхронная отсылка может идти в общую очередь с привязанным идентификатором канала, а эта очередь затем может разгребаться на пуле потоков.

Ибо тебе придётся эту одну очередь разгребать в одном месте.
Это и есть бутылочное горлышко.
А все то, что ты тут понаписал, вообще к делу отношения не имеет.

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

Это твои больные фантазии.
Все о чем я говорю, что за этим может следить сам канал.
На самом деле каналы даже регистрировать в одном месте не нужно.
Они вполне самостоятельны.

V>>>так и на предмет того, что канал вовсе не обязан иметь выделенный физический поток-обработчик сообщений.

WH>>Это тоже ни разу не проблема.
V>Разве? Ну тогда прямо сейчас стоит остановиться и внимательно посмотреть — а точно ли идет спор о разных вещах, или кто-то не умеет формулировать свои мысли? А то как бы не было опять смешно...
Это ты не можешь понять что:
1)В акторе всегда есть логический поток. Иначе состояние актора будет порвано на куски гонками.
2)Наличие логического потока не приводит к тому, что для этого потока нужно выделять персональный поток ОС.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[12]: Actor-based. Success story
От: vdimas Россия  
Дата: 02.07.12 11:09
Оценка:
Здравствуйте, Lazin, Вы писали:

L>Я тебе процитировал оригинальный RFC. Какое отношение к обсуждаемой теме имеют детали реализации конкретного сетевого стека я не могу понять если честно.


Это же ты сказал, что у меня алгоритм Нагля, и так не пояснил, в каком месте. А я тебе лишь показал, как реально работает сетка при включенном Нагле, бо ты указал выдержку менее 1% доки из которой сам же делаешь неверные выводы.

V>>В любом случае, даже в твоей "версии алгоритма Нагля" это и близко не то, что я предлагал делать для межпотоковых очередей. Даже если брать описание работы только одной стороны, то в алгоритме Нагля участвует размер кадра и размер окна (читать RFC-896 целиком) если данных на кадр хватает, то они отсылаются немедленно до тех пор, пока размер TCP-окна не больше текущего максимального.

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

Я же говорю, ТЫ НИЧЕГО НЕ ПОНИМАЕШЬ. Специально сообщение никто не буферизирует. (Мне даже любопытен твой ход мыслей — а какой в этом может быть толк???)

L>задерживать их тоже нельзя,


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


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


А с чего ты решил, что Акторы не тянут сообщения по 1-му? Хотя, даже еси ои их вытащат все имеющиеся за раз (предположим), обрабатывать ои их будут всё-равно по 1-му кроме случая явного распараллельвания внутри акторов.


L>Nagle это обеспечивает,


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

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


На самом деле ровно наоборот, такой подход показывает лучшие на сегодня задержки и пропускные способности. Просто ты не понял фокуса, так же как не понял Нагля. Ну и к тому же полностью умозрительно фантазируешь... Взял бы да сравнил со случаем прокачки через примитивы синхронизации по 1-му сообщению. Там пиковая производительность почти на порядок меньшая выходит. И что характерно, что у адекватный lock-free алгоритмов, работающих по описанному мной принципу, есть интересная особенность: чем больше нагрузка, тем дешевле полный цикл передачи одного сообщения. Во-первых из-за того, что стоимость самых дорогих операций размазывается на бОльшее кол-во сообщений, а во-вторых из-за того, что ожидающий поток почти не заходит в сон на ожидание. А это еще экономия 1-2us на цикл, помимо остальных операций.

L>Дальше — больше, если в нашей системе акторов есть куча переполненных очередей, то это может означать только одно — работу в режиме out of capacity. Тут нужно увеличивать capacity, либо увеличивать пропускную способность системы за счет распараллеливания тяжелых этапов обработки


Интересно, что даст лишнее распараллеливание, если кол-во физических ядер ограничено? А оно даст только лишние тормоза. Попробуй создать несколько тысяч потоков ОС и сравни быстродействие с системой на пуле из всего нескольких потоков. Тоже получишь разницу более порядка в пользу последнего варианта, особенно если научишься дешево помещать задачи в очередь к потокам и извлекать их оттуда. Конкретное кол-во потоков зависит от характера задач. На одих задачах для моего 6-тиядерника получаю максимум на 8-ти потоках, на других — на 14-ти. В общем, никакое внутреннее зрение тебе не поможет — только эксперимент. Кстате, рекомендую покурить, для чего вообще нужны фиберы, с чем они борятся.

L>или использования более быстрых алгоритмов,


Ага, хороший лозунг, годный. "Граждане, пишите хорошие программы!"

L>а не уменьшать издержки на CAS-ы при чтении из очередей.


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

Но я тебя на всяк случай сориентирую:
— штрафы за переключения контекстов или даже за холостой вызов ядерных примитивов синхронизации — от 1us и выше на топовых процах; На нетоповых порядка 3-х и выше.
— самый "сложный" алгоритм по обработке одного сообщения тоже требует порядка 1us, обходя при этом несколько тысяч узлов алгоритма;
— большинство остальных алгоритмов имеют стоимость от единиц/дестков до сотни-другой наносекунд;
— стоимость итерации по списку сообщений без interlocked или примитивов синхронизации — порядка 1-2ns на сообщение, с этими примитивами — в 100-1000 раз дороже в пересчете на сообщение. Т.е. простое обслуживание механики сравнимо по стоимости с самыми сложными алгоритмами в системе. Почему так — предлагаю помедитировать самостоятельно. Копать в направлении отрыва внутренней пропускной способности процессоров от внешней.


L>Вот такой батчинг как ты описал, подходит для записи в файл, например.


Неужели? Это из-за стоимости одной операции или у тебя другие соображения? А не предположишь стоимость одной операции по записи, скажем, 10 байт в файл? Не пробовал писать в цикле? А при неравномерной нагрузке? Поробуй, ты будешь очень удивлен, гарантирую.

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


V>>Т.е. ты как бэ не понимаешь собеседника (факт налицо) и я не уверен, стоит ли дальше распинаться...

L>Если тебя не понимают, то это твои проблемы, если не можешь внятно выразить свои мысли, так, чтобы тебя поняли, то может действительно не стоит

Уверен, коллеги всё поняли. Да и ты понял описанную технику, но споришь с ней сугубо умозрительно, не потрудившись провести и простейшего эксперимента перед этим. Еще и непониманием работы Нагля поделился. Поэтому сел в лужу минимум дважды в одном сообщении.
Re[11]: Actor-based. Success story
От: vdimas Россия  
Дата: 02.07.12 16:58
Оценка: -1 :)
Здравствуйте, WolfHound, Вы писали:

WH>Вот это твое предложение полнейший бред с алгоритмической точки зрения.

V>>>Цимус в том, что нет никакого смысла посылать сообщение конкретному каналу в общем случае. Даже если в Сингулярити это на уровне языка видится именно так, реально это может происходить не так. Асинхронная отсылка может идти в общую очередь с привязанным идентификатором канала, а эта очередь затем может разгребаться на пуле потоков.

Если уже был упомянут пул потоков, то не бред. Откуда вообще берется очередь, не хочешь прикинуть? Очередь — это то, что не может быть выполнено прямо сейчас. Поэтому у меня очередь не к агентам, а к вычислительным ресурсам. Кодирование цели — тоже разное. Иногда это текстовый адрес (для слабой связаности), где тогда ресолвинг адреса — эта требуемая часть динамического алгоритма by design. А иногда это конкретный экземпляр интерфейса получателя, в таком сценарии это ничем не отличается от асинхронного вызова делегата в другом потоке в дотнете.

WH>Ибо тебе придётся эту одну очередь разгребать в одном месте.

WH>Это и есть бутылочное горлышко.

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

WH>А все то, что ты тут понаписал, вообще к делу отношения не имеет.


Это твой пример с мейл-боксом отношения к делу не имеет, потому что кривее аналогию было бы не так просто изобрести. Если уж приводить аналогии из доставки мыла, то тут надо смотреть выше — каждый мейл-сервер — это агент, а инфраструктура интернета — среда передачи. Мейл-сервера передают друг другу сообщения по мере их поступления, безо-всякого selective receive. А то, что клиенту мейл-сервера надо выдать только его сообщения по требованию — это уже система с ограничениями, которая не может служить иллюстрацией к общему случаю. Ведь у клиента конкретного мейл-бокса свои вычислительные ресурсы, которые он пожелал состыковать на время передачи с ресурсами сервера. В агентской среде на одной физической машине сценарий прямо противоположный — клиент получает тики тогда, когда для него есть "почта", а не когда ему приспичит.


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

WH>Это твои больные фантазии.

Сам дурак.

WH>Все о чем я говорю, что за этим может следить сам канал.

WH>На самом деле каналы даже регистрировать в одном месте не нужно.
WH>Они вполне самостоятельны.

Только на слишком поверхностный взгляд. Каналы не самостоятельны ни разу. Если процесс сдох по какой-то причине, канал надо оповестить. Ну и каналу надо дать тики процессорного времени, не находишь?

V>>Разве? Ну тогда прямо сейчас стоит остановиться и внимательно посмотреть — а точно ли идет спор о разных вещах, или кто-то не умеет формулировать свои мысли? А то как бы не было опять смешно...

WH>Это ты не можешь понять что:
WH>1)В акторе всегда есть логический поток.

Наконец-то! Тебе с этого стоило начинать.

Это ты про что-то своё. Теперь я понимаю, откуда растут ноги твоего "поток прибит гвоздями к сущности". Блин, редкостная по-кривине модель. Согласен на все 100%. Потому что это на самом деле модель потока исполнения, и ничего больше, а не агента-сущности.

Понимаешь... поток исполнения не принято награждать чем-то высокоуровневым. Согласен, при попытке приписать потоку "сознание" выходит кривизна. Правильно ты тут заметил: http://www.rsdn.ru/forum/philosophy/4795688.1.aspx
Автор: WolfHound
Дата: 28.06.12
Мде, коллега, это залет.. Ты расписался что не понимаешь, что поток — это ресурс, а программная сущность — это потребитель ресурса. (Даже логический поток, а в любой ОС потоки логические ес-но). Но у тебя ресурс смешивается с потребителем... ну и каша...


WH>Иначе состояние актора будет порвано на куски гонками.


У какой-нить утилитки проброса TCP-портов такое поведение — by-design (исходники скинуть?). Её задача и состоит в умении вычислять корректное взаимное состояние 2-х независимых соединений, которые генерят события асинхронно.


WH>2)Наличие логического потока не приводит к тому, что для этого потока нужно выделять персональный поток ОС.


Да не важно. Синхронная модель заметно ограниченее асинхронной, я тут даже обсуждать не хочу. У себя я предоставил возможность создавать такие агенты, чтобы была гарантированная очередность сообщений к ним. Это полный аналог приложения [мульти-]STA (это до сих пор самая популярная модель). Для многих "линейных" задач вполне покатит...

Маршаллинг в стиле STA был сделан на сортированных буферах "внутри" самого агента. Вернее так: эта политика была реализована через агента, который является прокси к целевому, беря на себя все вопросы синхронизации. Причем, у меня было две реализации — одна через блокировки, а другая — с собственным дополнительным потоком ОС. Но это частные случаи, ес-но (дополнительному потоку надо было дать высочайший возможный приоритет.. это нормально для мультимедиа).
Re: Actor-based. Success story
От: PSV100  
Дата: 03.07.12 09:51
Оценка: 1 (1)
Здравствуйте, Буравчик, Вы писали:

Б>У кого-нибудь есть опыт участия в достаточно больших проектах, архитекутра которых была бы основана на акторах? Т.е. система разбивалась на независимые компоненты, которые обмениваются сообщениями (и только сообщениями). Конечно, вызов методов — это тоже, в некотором роде, посылка сообщений, но интересуют системы, построенные на "настоящих" сообщениях, т.е. компонент имеет очередь сообщений и явно обрабатывает их (как в Erlang).

Б>Какие языки/библиотеки использовались?
Б>Удобно ли сопровождать (понимать, расширять, изменять) такие системы?
Б>Какие есть минусы и плюсы actor-based?
Б>Для чего actor-based стоит применять, а для чего нет?
Б>Поделитесь опытом и мыслями.

Ссылки по теме, может дадут полезных мыслишек:

— модель многопоточночти в Clojure, там же есть небольшая критика модели акторов. Здесь ещё нужно учитывать потенциал для реализации в плане эффективности/производительности;

— ещё одна альтернатива: Disruptor, здесь общее описание, здесь его неплохо разобрали;

здесь есть примерчик для облегчения трассировки событий в Эрланге, когда программа строит диаграммы последовательностей (навеяно обсуждаемыми рядом ДРАКОНами и прочими схемами).
Re[12]: Actor-based. Success story
От: WolfHound  
Дата: 03.07.12 10:05
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Если уже был упомянут пул потоков, то не бред.

Полнейший берд.
Ибо в пул потоков нужно засовывать не сообщения как ты предлагаешь.
А готовые к исполнению процессы.

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

V>Откуда вообще берется очередь, не хочешь прикинуть? Очередь — это то, что не может быть выполнено прямо сейчас.

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

WH>>Ибо тебе придётся эту одну очередь разгребать в одном месте.

WH>>Это и есть бутылочное горлышко.
V>Так работают любые ОС. Планирование ресурсов — всегда централизованное.
Это твои фантазии.

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

Ох. Ты даже деревьев не видишь.
На листиках зациклился.

V>Это твой пример с мейл-боксом отношения к делу не имеет, потому что кривее аналогию было бы не так просто изобрести.

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

V>Только на слишком поверхностный взгляд. Каналы не самостоятельны ни разу. Если процесс сдох по какой-то причине, канал надо оповестить.

Умирающий процесс, который держит конец канала и оповестит.
Если он последний, то он и убьёт ставший никому не нужным канал.
Тоже мне бином Ньютона.

V>Ну и каналу надо дать тики процессорного времени, не находишь?

Это совсем бред. Канал штука совершенно пассивная. И процессорные тики получает от того кто этот канал дергает в тот момент когда его дергают.
Все остальное время канал занимает только память.

WH>>1)В акторе всегда есть логический поток.

V>Наконец-то! Тебе с этого стоило начинать.
Я с этого и начал. Уже которое сообщение это тебе повторяю.

V>Это ты про что-то своё.

Нет. Я это про модель акторов.

V>Теперь я понимаю, откуда растут ноги твоего "поток прибит гвоздями к сущности". Блин, редкостная по-кривине модель. Согласен на все 100%. Потому что это на самом деле модель потока исполнения, и ничего больше, а не агента-сущности.

У каждого актора есть свой поток.
Всегда.
Ибо у актора есть состояние.
Обработка каждого сообщения использует и в некоторых случаях меняет это состояние.
Обработка сообщения всегда должна видеть согласованное состояние. Те читать и писать одновременно нельзя.
Две обработки сообщения не могут менять состояние одновременно.
Таким образом, у нас возникает логическая последовательность, в которой происходит обработка сообщений.
Это и есть поток.
rwlock'и, транзакции итп это уже оптимизации. И к модели отношения не имеют.

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

V>Понимаешь... поток исполнения не принято награждать чем-то высокоуровневым. Согласен, при попытке приписать потоку "сознание" выходит кривизна. Правильно ты тут заметил: http://www.rsdn.ru/forum/philosophy/4795688.1.aspx
Автор: WolfHound
Дата: 28.06.12
Мде, коллега, это залет.. Ты расписался что не понимаешь, что поток — это ресурс, а программная сущность — это потребитель ресурса. (Даже логический поток, а в любой ОС потоки логические ес-но). Но у тебя ресурс смешивается с потребителем... ну и каша...

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

V>У какой-нить утилитки проброса TCP-портов такое поведение — by-design (исходники скинуть?). Её задача и состоит в умении вычислять корректное взаимное состояние 2-х независимых соединений, которые генерят события асинхронно.

Заводим по процессу на соединение и вперед.
Не забывай, что есть не только пальмы, но и ёлки.

V>Маршаллинг в стиле STA был сделан на сортированных буферах "внутри" самого агента. Вернее так: эта политика была реализована через агента, который является прокси к целевому, беря на себя все вопросы синхронизации. Причем, у меня было две реализации — одна через блокировки, а другая — с собственным дополнительным потоком ОС. Но это частные случаи, ес-но (дополнительному потоку надо было дать высочайший возможный приоритет.. это нормально для мультимедиа).

Какой феерический бред с алгоритмической точки зрения.
И после такого ты еще набираешься наглости учить других.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Actor-based. Success story
От: mima  
Дата: 03.07.12 13:35
Оценка: 9 (3)
Здравствуйте, Буравчик, Вы писали:

Б>У кого-нибудь есть опыт участия в достаточно больших проектах, архитекутра которых была бы основана на акторах? Т.е. система разбивалась на независимые компоненты, которые обмениваются сообщениями (и только сообщениями). Конечно, вызов методов — это тоже, в некотором роде, посылка сообщений, но интересуют системы, построенные на "настоящих" сообщениях, т.е. компонент имеет очередь сообщений и явно обрабатывает их (как в Erlang).


Не сильно большая система, примерно 5 разных программ, запущенных на нескольких серверах, общающихся друг с другом. 3 из них содержат разной степени сложности иерархию акторов, 2 другие — клиенты с примитивными акторами-слушателями. Есть и другие программы — части этой системы, но они не actor-based, поэтому не упоминаю.

Б>Какие языки/библиотеки использовались?


Scala/Akka.

Б>Удобно ли сопровождать (понимать, расширять, изменять) такие системы?


Ожидания оправдались. К сожалению, в то время когда всё это писалось у Akka не было durable mailboxes, потом написать свой диспетчер было сложновато, поэтому некоторые части реализованы не так идеально как хотелось бы. Но даже тогда таких пунктиков было мало, сразу находились нужные вещи: супервайзеры, лоадбалансеры, роутеры, пулы акторов, ActorRegistry, лёгкое подключение remote-акторов и много чего ещё реализовано и готово к работе.

С помощью actor-based подхода легко писать модульно, поэтому пишешь более модульно. Из-за этого, кроме облегчения в поддержке, мы смогли легко нарастить доп. функциональность, которая сильно облегчила нам работу. Её бы просто не было, если бы не было принято решение о разбиении системы на столь мелкие при обычной разработке части. Хотя это косвенная заслуга actor-based.

Понимать систему просто, если знаешь иерархию — лучше иметь рисунок. Сами акторы простые, пишешь их как можно более иммутабельными и быстрыми. Т.к. работают они по сути в одном потоке, и данные свои меняют тоже в одном, то с concurrency проблем нет. Хотя обдумывать их lifecycle надо, но это один раз: let it crash работает.

Расширять/изменять — зависит от. Если код одного актора править, или даже нескольких — то это обычно очень быстро и просто. Если иерархию, то напряжения больше, но это делается гораздо реже. Есть чёткое разделение между иерархией и "рабочими" акторами.

Б>Какие есть минусы и плюсы actor-based?


Слишком общий вопрос, пропущу.

Б>Для чего actor-based стоит применять, а для чего нет?


Мало смысла, если пишешь однопоточную монолитную систему: например, десктопная программка, которой ничего не надо вычислять в фоне.

В нашем случае система должна была быть модульной, просто в силу задачи, должна уметь шариться по разным машинам, быть масштабируемой, внутри модулей код должен быть параллельным. Тут actor-based напрашивался.

Б>Поделитесь опытом и мыслями.


Ну вот, вкратце.
Re[12]: Actor-based. Success story
От: vdimas Россия  
Дата: 04.07.12 22:09
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

WH>Значит, тебе придется упорядочить обработку этих сообщений.

WH>И получили поток.

Если нужно поток, можно взять STA-like апартмент. Только они дорогие, хотя местами это оправдано/удобно (особенно когда какой-то задаче надо дать специальные приоритеты на уровне ОС, тогда нужно сопоставить задаче поток уровня ОС).

WH>Максимум что можно сделать, это навернуть транзакционную память. Но даже с ней у тебя всё равно получается строгая последовательность изменений состояния.


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

V>>Это на уровне одного канала, считай что ничего. В реальных приложениях смысла в одном процессе с одним каналом очень немного. Это только где-то на самых "концах" системы, типа асинхронного логгера. Даже сложно придумать задачу, где бы был достаточен один канал на одно приложение, кроме этого логгера... не подскажешь?

WH>Никто не мешает проверять сколько угодно каналов одновременно в одном процессе.
WH>Тривиальная задача.

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

Кароч, мне как раз по работе приходится все эти сценарии из всевозможных позиций иметь. Приходится и как ты сказал (через poll/select списка дескрипторов) и как я рекомендую — в чистом асинхронном виде. Твой сценарий — самый неудобный и немасштабируемый. Как пример — в сети есть сравнительные данны по замерам libevent в различных режимах. На предложенной тобой технике-аналоге poll//select масштабируемость никакая и, начиная с определенного кол-ва дескрипторов, это всё настольуо безбожно сливает асинхронным решениям, что мне лень это дале обсуждать, сорри.

Твоё мнения я услышал. Оно противоречит данным мн-ва экспериментов. Обсуждение для меня закончено.


V>>Я так понимаю, что привести подтверждающий пример проблемы составить не должно?

WH>Это ты говоришь, что без DI-контейнера SRP соблюсти нельзя.
WH>Вот ты и доказывай.

Нет, я утверждал, что ты путаешь DI-процесс и DI-контейнер, завтавляя меня отвечать на утверждения, которые я не делал. Еще я утверждал, что качественное SRP недостижимо без трюка IoC, а любое IoC потом компенсируется DI-процессами — это by design и это не перепрыгнуть никак. Короче, я хз зачем ты вообще решил спорить по этой теме.
Re[13]: Actor-based. Success story
От: vdimas Россия  
Дата: 04.07.12 22:50
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

WH>Ибо в пул потоков нужно засовывать не сообщения как ты предлагаешь.

WH>А готовые к исполнению процессы.

Покажи на пальцах или псевдокоде в каком порядке их туда засовывать и почему именно так?

WH>Но даже это плохая модель.

WH>Гораздо эффективнее завести несколько физических потоков и создать по шедуллеру в каждом.
WH>Каждый процесс будет знать свой текущей шедуллуер и при получении сообщения будет оповещать свой шедуллер что он готов к работе.

Ну ты бы попробовал сначала, а потом бы тебе стало очень стыдно. Ты описал принцип работы мульти-STA и близкой к нему кооперативной многозадачности. Очень частный случай с самой хреновой балансировкой нагрузки из всех известных. Если какой-то твой логический процесс будет тяжеловесным, то остальные неудачники на том же "шедуллере" банально отсосут. Хотя я упоминал, что и этот вариант был сделан как частный случай.


V>>Откуда вообще берется очередь, не хочешь прикинуть? Очередь — это то, что не может быть выполнено прямо сейчас.

WH>Очередь в данном контексте это логический примитив общения между строго одним производителем и строго одним потребителем. Реализующий политику доставки первый пришёл первый ушёл.
WH>Все остальное детали реализации.

Это не ответ на вопрос — почему вообще образуется очередь. Попробуй еще раз. Если что — освежи предмет СМО перед ответом... Ах да... там же ненавистный матан... Тогда прими мои соболезнования.


WH>>>Ибо тебе придётся эту одну очередь разгребать в одном месте.

WH>>>Это и есть бутылочное горлышко.
V>>Так работают любые ОС. Планирование ресурсов — всегда централизованное.
WH>Это твои фантазии.

Гы, так даже не в курсе, как всё работает? )))

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

WH>Ох. Ты даже деревьев не видишь.
WH>На листиках зациклился.

Скоро я зациклюсь на твоих бесполезных комментах.

V>>Это твой пример с мейл-боксом отношения к делу не имеет, потому что кривее аналогию было бы не так просто изобрести.

WH>Ох.
WH>Терминологией не владеешь.

??? Терминологией мейл-боксов? )))

WH>Почтовый ящик это логический примитив общения между множеством производителей и строго одним потребителем. Порядок доставки сообщений не определен.


Всё ясно. Тот момент, что клиент мейл-бокса и мейл-сервер в общем случае имеют независимые вычислительные ресурсы, ты таки не понял. ЧТД.


V>>Только на слишком поверхностный взгляд. Каналы не самостоятельны ни разу. Если процесс сдох по какой-то причине, канал надо оповестить.

WH>Умирающий процесс, который держит конец канала и оповестит.

Не оповестит при аварийном выходе.

WH>Если он последний, то он и убьёт ставший никому не нужным канал.


Это только в песочницах возможно... в которых сферокони пасутся.


V>>Ну и каналу надо дать тики процессорного времени, не находишь?

WH>Это совсем бред. Канал штука совершенно пассивная. И процессорные тики получает от того кто этот канал дергает в тот момент когда его дергают.

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


WH>>>1)В акторе всегда есть логический поток.

V>>Наконец-то! Тебе с этого стоило начинать.
WH>Я с этого и начал. Уже которое сообщение это тебе повторяю.

V>>Это ты про что-то своё.

WH>Нет. Я это про модель акторов.

Это не модель акторов, а некая удобная тебе модель с ограничениями, которые необязательны. И вот ты вызвался критиковать собственное представление об акторах. Браво.


V>>Теперь я понимаю, откуда растут ноги твоего "поток прибит гвоздями к сущности". Блин, редкостная по-кривине модель. Согласен на все 100%. Потому что это на самом деле модель потока исполнения, и ничего больше, а не агента-сущности.

WH>У каждого актора есть свой поток.
WH>Всегда.
WH>Ибо у актора есть состояние.

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

WH>Обработка каждого сообщения использует и в некоторых случаях меняет это состояние.

WH>Обработка сообщения всегда должна видеть согласованное состояние. Те читать и писать одновременно нельзя.

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


WH>Две обработки сообщения не могут менять состояние одновременно.


Могут, потому что у состояния есть многомерное пространство.

WH>Таким образом, у нас возникает логическая последовательность, в которой происходит обработка сообщений.


В STA возникает. Иначе — исходим из асинхронности. Агент по твоей модели будет глуп до невозможности. Ему даже нельзя будет отменить какую-нить тяжеловесную операцию... Ведь он их исполняет сугубо последовательно. Это то, почему STA непопулярно — оно провоцирует на глупый код.


WH>Это и есть поток.


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

WH>rwlock'и, транзакции итп это уже оптимизации. И к модели отношения не имеют.


Транзакции — это не оптимизации, а условия существования апартментов, отличных от STA. Это уровень дизайна.

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


Можем проглотить десятки тыщ, генерящих сотни событий в секунду каждый. Правда, это та система, что не на дотнете... на дотнете надо ровно на порядок скромнее быть... И оптимизации смысл имеют, ес-но. Просто в твоей модели они невзможны. Например, любой lock-free теряет всякий смысл.

WH>Ибо есть ОС в которых потоки ОС можно плодить в любых количествах без проблем с производительностью.

WH>Например, та же сингулярити может создавать и шуделлить процессы в любом количестве. Ибо там не используется аппаратная защита и шедуллеры ОС могут сидеть на каждом аппаратном потоке и шедуллить не хуже чем твои юзермоде шедуллеры которыми ты так гордишься.

Кривизну этой модели я уже показал. Не верю, что в сингулярити настолко топорно. Скорее, ты что-то недополнял.

WH>И никто не мешает создать свою сингулярити внутри одного процесса винды.


Ну так создай и позамеряй, какие проблемы?


V>>У какой-нить утилитки проброса TCP-портов такое поведение — by-design (исходники скинуть?). Её задача и состоит в умении вычислять корректное взаимное состояние 2-х независимых соединений, которые генерят события асинхронно.

WH>Заводим по процессу на соединение и вперед.

И еще третий, обслуживать взаимное состояние этих двух. Садись, два.

WH>Не забывай, что есть не только пальмы, но и ёлки.


Много пил?


V>>Маршаллинг в стиле STA был сделан на сортированных буферах "внутри" самого агента. Вернее так: эта политика была реализована через агента, который является прокси к целевому, беря на себя все вопросы синхронизации. Причем, у меня было две реализации — одна через блокировки, а другая — с собственным дополнительным потоком ОС. Но это частные случаи, ес-но (дополнительному потоку надо было дать высочайший возможный приоритет.. это нормально для мультимедиа).

WH>Какой феерический бред с алгоритмической точки зрения.
WH>И после такого ты еще набираешься наглости учить других.

(1) Как всегда 0 аргументов.
(2) Забываешь перед прочтением влючать процессор.
(2-a) В скорее всего просто не в теме и кидаешь сугубо умозрительные понты.

Попытаюсь тебя сосредоточить на сути решения: никто в здравом уме не будет делать выделенный STA-поток посто так. Зачем так было сделано — в абзаце написано. Буфер с сортировкой для мультимедиа обязателен. Специальный приоритет на "нейтивном" потоке ОС — тоже.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.