Здравствуйте, remark, Вы писали:
R>А нету ли случаем для SObjectizer какого-то краткого списка поддерживаемых фич и компонентов, типа документации Doxуgen по классам. Вроде на eao197.narod.ru и sourceforge не видно. Типа как здесь. R>Чего хотелось бы — хотелось бы, что бы можно было это быстро просмотреть и оценить , что есть и как оно есть, а чего нет. R>Ну вот, например, по ссылке в ACE можно сразу посмотреть — "так, ACE_RW_Mutex там есть, функции TryLock() предоставляет" и т.д.
Doxygen документация по SObjectizer есть: вот, например -- оно?
Есть там, конечно, недочеты, ведь мы написали основной объем кода в SObjectizer был написан еще до того, как начали использовать Doxygen.
R>Ещё такой вопрос. То, что синхронного взаимодействия "нет и нет будет", я понял... ну в принципе наверное и правильно... R>А тем не менее нету ли какой-то другой поддержки паттерна запрос-ответ в фреймворке? R>Понятно, что можно вручную отослать некий request_id, получатель вставит его в ответ, а потом проверять его и т.д. Но нету ли каких-то шорт-катов для поддержки такого взаимодействия? R>Например, есть агент агент_читающий_настройки_из_конфигурационного_файла. К нему обращаются множество других клиентов с запросом считать такой-то параметр. А он потом отвечает другим сообщением, в котором идёт само значение параметра. R>Хотелось бы, что бы как-то автоматически сматчился запрос и ответ и ответ попал только тому агенту, который отправил запрос, а не ко всем. Если ещё агенты сидят в разных потоках, то будет thundering herd problem. R>Или такая задача решается как-то по другому в SObjectizer?
Нет, пока готовых рецептов для таких вещей нет. Но, я буду признателен, если подобные предложения будут поступать и, скажем фиксироваться в feature requests на SourceForge.
По поводу отсылки сообщения-ответа конкретному получателю могу навскидку предложить такой вариант:
* в сообщении-запросе передавать отдельным полем имя агента-инициатора запроса;
* ответное сообщение будет отсылаться целенаправлено тому агенту, имя которого было в запросе.
R>Ещё заодно по поводу состояний объектов. А действительно часто необходимы состояния в реальных задачах? Ты не мог бы привести какие-то более-менее реальные примеры агентов, которым действительно полезны состояния. Ну кроме коммуникационного канала, у которого есть state_connected, state_disconnected и т.д. R>А то я вот думаю, может быть поддержку состояний более целессобразно отдавать самому агенту... Ну я агентов пока много не делал, поэтому самому не получается оценить...
Я сейчас сделал поиск по одному из самых больших своих проектов на SObjectizer-е. Оказалось, что самое большое количество состояний как раз у агентов, которые либо обрабатывают входящие/исходящие соединения (те самые st_connecting, st_connected, st_disconnected), либо сами являются некоторым оконечными точками. У остальных агентов либо одно состояние (st_normal), в котором выполняется вся работа, либо два-три состояния (st_initial, в котором агент начинает сам себя раскручивать, st_configured -- когда агент полностью готов к работе, st_not_configured -- когда работа невозможна из-за ошибок конфигурирования).
Но могу привести пару примеров с состояниями:
1) стабилизатор исходящего трафика -- агент, задача которого выдавать исходящие пакеты в заданном темпе. Хотя сами пакеты могут приходить к нему в произвольном темпе. У данного агента всего два состояния: st_free, когда он свободен и может отправить исходящий пакет дальше. И st_timeout, когда нужно выждать паузу перед отсылкой следующего пакета. Упрощенный принип таков -- когда агент в состоянии st_free, то исходящий пакет сразу идет наружу, а агент переходит в состояние st_timeout и оправляет сам себе сообщение msg_timeout. Пока агент находится в st_timeout все исходяшие пакеты блокируются. Когда в st_timeout он получает msg_timeout, он возвращается в состояние st_free.
2) агент, который контролирует работу внешнего процесса с автоматическим перезапуском в случае падения внешнего процесса. Там есть состояния (если не ошибаюсь): st_launching (в это время внешнему процессу дается шанс на успешный стар), st_started (внешний процесс успешно запущен и работает), st_stopping (в это время внешнему процессу дается шанс корректно завершить свою работу), st_stopped (внешний процесс не работает).
Такие простые наборы состояний, тем не менее, позволяют лучше представить себе работу агента по его декларативному описанию. Еще одна важная вещь -- обработчики входа/выхода в/из состояния выполняют важный объем работы. Например, когда агент входит в состояние st_launcing, он:
— стартует процесс,
— оправляет самому себе отложенное сообщение, по пришествии которого будет проверено, работает ли запущенный процесс или нет.
Чем-то состояния и обработчики входа/выхода позволяют реализовывать агентов довольно близко к тому, как логика работы агентов могла бы быть представлена на UML диаграмме состояний.
Еще одна полезная фича состояний, которая проявляется при использовании специального фреймворка для мониторинга SObjectizer-а: состояния агента можно видеть из-вне приложения. И на основании имени состояния строить предположение о том, что происходит с приложением. Вот, например, st_bound_trx -- это имена состояний агентов:
Этот фреймворк так же со временем будет опубликован на SourceForge.
R>А можно ли в рамках SObjectizer реализовать т.н. фильтры? R>Под фильтрами я имею в виду следующее. Допустим есть некий агент агент_достающий_значения_из_бд. Агент отлаженный и имеющийся в качестве готового компонета. Допустим он обрабатывает сообщения do_read_value, а после считывания данных из бд отвечает сообщением on_read_value. И допустим есть уже агента-клиенты, которые пользуются этим агентом. R>Я хочу добавить в систему агент_который_кэширует_значения_из_бд, причём прозрачно и для агента-сервера и для агентов-клиентов. Т.е. агент_который_кэширует_значения_из_бд регистрируется как фильтр на сообщения do_read_value, если требуемое значение есть в его кэше, то он сразу отвечает on_read_value и отменяет дальнейшую обработку сообщения, если значения в кэше нет, то он передаёт управление "дальше". Когда же идёт ответное on_read_value, то агент_который_кэширует_значения_из_бд должен его тоже перехватить и закэшировать и передать "дальше". R>Имхо для систем именно компонентных и именно компонуемых из готовых компонетов, а я так понимаю, что это одно из серьёзных приемуществ агентных систем, такая функциональность была бы очень полезной...
В чистом SObjectizer-е такой возможности нет. У меня были кое-какие мысли по поводу организации перехвата сообщений. Но удачного решения я не нашел
Возможность перехвата сообщений у нас сделана на основе отдельной библиотеки mbapi (message box api), которая построена поверх SObjectizer. Как раз там то, что ты описал и используется на полную катушку. И это действительно очень удобно и востребованно. Библиотека mbapi так же будет опубликована на SourceForge.
Подозреваю, что возник вопрос -- когда же все это будет опубликовано
Ответить на него не просто. Я бы очень хотел, чтобы финальная версия SObjectizer 4.4 вышла в этом году (ближе к концу). А до этого запланировано, как минимум, еще две бета-версии. Часть библиотек, которые мы создали поверх SObjectizer, хотелось бы серьезно переработать -- многие из них создавались достаточно давно и, поэтому, содержат много чего устаревшего. Особенно это касается мониторинга и mbapi. Но, надеюсь, к концу года и они будут опубликованы.
R>И ещё последний момент. Раз ты этим занимался, наверное у тебя ссылочки на другие подобные агентные фреймворки... ты не мог бы что-нибудь подкинуть... R>Ну вот типа как я кидал на OSE Event Driven Systems R>Интересуют ссылки именно на реальные, так сказать промышленные фреймворки/библиотеки, а не теоретические ресёрчи. В принципе на любых языках, приемущественно, конечно, C++, но пойдёт и C#/Java.
Что касается именно агентных фреймворков, то я о таких не слышал (опять же, чукча не читатель, чукча писатель ). Об агентных системах упоминалось в книге Распределенные системы. Принципы и парадигмы
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>А нету ли случаем для SObjectizer какого-то краткого списка поддерживаемых фич и компонентов, типа документации Doxуgen по классам
E>Doxygen документация по SObjectizer есть: вот, например -- оно?
Оно. Спасибо.
E>Нет, пока готовых рецептов для таких вещей нет. Но, я буду признателен, если подобные предложения будут поступать и, скажем фиксироваться в feature requests на SourceForge.
А там по-русски можно?
Ну вообще это будет не совсем честный реквест, т.к. я собственно пользователем sobjectizer не являюсь...
E>По поводу отсылки сообщения-ответа конкретному получателю могу навскидку предложить такой вариант: E>* в сообщении-запросе передавать отдельным полем имя агента-инициатора запроса; E>* ответное сообщение будет отсылаться целенаправлено тому агенту, имя которого было в запросе.
И что бы отправлялось оно тому, кто послал запрос автоматически, т.е. что бы отправитель содержался в сообщении неявно. И что бы запрос содержался в ответе тоже автоматически...
E>Я сейчас сделал поиск по одному из самых больших своих проектов на SObjectizer-е. Оказалось, что самое большое количество состояний как раз у агентов, которые либо обрабатывают входящие/исходящие соединения (те самые st_connecting, st_connected, st_disconnected), либо сами являются некоторым оконечными точками. У остальных агентов либо одно состояние (st_normal), в котором выполняется вся работа, либо два-три состояния (st_initial, в котором агент начинает сам себя раскручивать, st_configured -- когда агент полностью готов к работе, st_not_configured -- когда работа невозможна из-за ошибок конфигурирования).
E>Но могу привести пару примеров с состояниями:
Понятно. Т.е. состояния есть, просто надо научится думать немного по-другому, чтобы выделять состояния, т.к. если не думать особым образом, то наверное всё это будет хотеться реализовывать "обычной" логикой.
E>Чем-то состояния и обработчики входа/выхода позволяют реализовывать агентов довольно близко к тому, как логика работы агентов могла бы быть представлена на UML диаграмме состояний.
А вот это интересно, об этом я не подумал...
E>Еще одна полезная фича состояний, которая проявляется при использовании специального фреймворка для мониторинга SObjectizer-а: состояния агента можно видеть из-вне приложения. И на основании имени состояния строить предположение о том, что происходит с приложением. Вот, например, st_bound_trx -- это имена состояний агентов: E> E>Этот фреймворк так же со временем будет опубликован на SourceForge.
Круто! Именно таких вещей обычно не хватает библиотекам.
R>>А можно ли в рамках SObjectizer реализовать т.н. фильтры? R>>Под фильтрами я имею в виду следующее. Допустим есть некий агент агент_достающий_значения_из_бд. Агент отлаженный и имеющийся в качестве готового компонета. Допустим он обрабатывает сообщения do_read_value, а после считывания данных из бд отвечает сообщением on_read_value. И допустим есть уже агента-клиенты, которые пользуются этим агентом. R>>Я хочу добавить в систему агент_который_кэширует_значения_из_бд, причём прозрачно и для агента-сервера и для агентов-клиентов. Т.е. агент_который_кэширует_значения_из_бд регистрируется как фильтр на сообщения do_read_value, если требуемое значение есть в его кэше, то он сразу отвечает on_read_value и отменяет дальнейшую обработку сообщения, если значения в кэше нет, то он передаёт управление "дальше". Когда же идёт ответное on_read_value, то агент_который_кэширует_значения_из_бд должен его тоже перехватить и закэшировать и передать "дальше". R>>Имхо для систем именно компонентных и именно компонуемых из готовых компонетов, а я так понимаю, что это одно из серьёзных приемуществ агентных систем, такая функциональность была бы очень полезной...
E>В чистом SObjectizer-е такой возможности нет. У меня были кое-какие мысли по поводу организации перехвата сообщений. Но удачного решения я не нашел
А в чём была проблема? В том как это реализовать с т.з. пользователя или как это реализовать внутри или прикрутить к существующему фреймворку?
E>Возможность перехвата сообщений у нас сделана на основе отдельной библиотеки mbapi (message box api), которая построена поверх SObjectizer. Как раз там то, что ты описал и используется на полную катушку. И это действительно очень удобно и востребованно. Библиотека mbapi так же будет опубликована на SourceForge.
А на сколько она интегрируется с самим SObjectizer?
Т.е. как бы это сказать, насколько агенты mbapi являются агентами SObjectizer и наоборот. Т.е. mbapi — это полная обёртка над SObjectizer, как MFC над WinAPI или приложение пишется на SObjectizer и mbapi охватывает только некоторые части...
E>Подозреваю, что возник вопрос -- когда же все это будет опубликовано E>Ответить на него не просто. Я бы очень хотел, чтобы финальная версия SObjectizer 4.4 вышла в этом году (ближе к концу). А до этого запланировано, как минимум, еще две бета-версии. Часть библиотек, которые мы создали поверх SObjectizer, хотелось бы серьезно переработать -- многие из них создавались достаточно давно и, поэтому, содержат много чего устаревшего. Особенно это касается мониторинга и mbapi. Но, надеюсь, к концу года и они будут опубликованы.
E>Ближе всего к SObjectizer, как мне кажется, системы обмена сообщениями. Например, TIBCO Randevouz. Или OpenSource библиотека Spread Toolkit.
В первую очередь нужно избавляться от синхронизации
...
Может быть, подсчет ссылок получится заменить lock-free списками для событий/сообщений/агентов и это позволит избавится от синхронизации. Но это уже направление для дальнейших работ.
Если у тебя до этого дойдут руки, то я, возможно, мог бы чем-нибудь посодействовать...
Я имею в виду в плане lock-free структур данных.
Только, единственное, что было бы желательно сделать (но в прочем это было бо желательно сделать в любом случае) — сделать замеры производительности на многоядерной машине, в силу того, что они уже начинают входить в мейнстрим, а высокопроизводительные машины уже некоторое время многоядерные/многопроцессорные, и самое главное, что к этому всё неизбежно движется. Сейчас уже продаются 4-ёх ядерные процессоры, а самое интересное начнётся, когда появятся и будут в каждом ПК 8/16 и т.д. ядерные процессоры, и в каждом по несколько аппаратных контекстов lock-based структуры при переходе на многоядерные процессоры показывают практически нулевую масштабируемость, а lock-free близкую к линейной. Вот тут и начнётся самое интересное — как говорится, кто не спрятался, я не виноват
Поэтому даже сейчас было бы очень интересно поглядеть на результаты бенчмарков на 2 и 4 ядерных/процессорных машинах и оценить масштабируемость фреймворка.
Мой интерес какой? Что бы не было непонимания
Мне было бы интересно поглядеть на импакт внедрения lock-free структур в большие/реальные проекты, конкретно в цифрах, поглядеть как цифры будут зависеть от количества ядер, сравнить с lock-based структурами. Собственно получить опыт такого внедрения, поглядеть, возникают ли какие-то проблемы и т.д.
Здравствуйте, remark, Вы писали:
E>>Нет, пока готовых рецептов для таких вещей нет. Но, я буду признателен, если подобные предложения будут поступать и, скажем фиксироваться в feature requests на SourceForge.
R>А там по-русски можно?
Можно. Пока там все осуждения идут на русском.
R>Ну вообще это будет не совсем честный реквест, т.к. я собственно пользователем sobjectizer не являюсь...
Может как раз реагирование на твои пожелания и позволят перевести тебя в число пользователей sobjectizer
E>>По поводу отсылки сообщения-ответа конкретному получателю могу навскидку предложить такой вариант: E>>* в сообщении-запросе передавать отдельным полем имя агента-инициатора запроса; E>>* ответное сообщение будет отсылаться целенаправлено тому агенту, имя которого было в запросе.
R>Понятно.
R>Я имею в виду что-то типа такого:
R>
R>И что бы отправлялось оно тому, кто послал запрос автоматически, т.е. что бы отправитель содержался в сообщении неявно. И что бы запрос содержался в ответе тоже автоматически...
Возможно, этого же можно достичь на прикладном уровне, введя некоторый базовый тип msg_with_request_id_t, в котором будет содержаться информация для отсылки ответа. И вспомогательный метод/свободную функцию answer_for, которая получив наследника msg_with_request_id_t сама выполняет отсылку ответного сообщения.
R>>>Имхо для систем именно компонентных и именно компонуемых из готовых компонетов, а я так понимаю, что это одно из серьёзных приемуществ агентных систем, такая функциональность была бы очень полезной...
E>>В чистом SObjectizer-е такой возможности нет. У меня были кое-какие мысли по поводу организации перехвата сообщений. Но удачного решения я не нашел
R>А в чём была проблема? В том как это реализовать с т.з. пользователя или как это реализовать внутри или прикрутить к существующему фреймворку?
В том, что сейчас нет т.н. очереди сообщений. Функции send_msg работают параллельно друг-другу, синхронизируя свои операции только на некоторых этапах. В момент обработки send_msg определяются все получатели сообщения и заявки на выполнение событий поступают в очереди заявок. Такая схема означает, что анализ и перехват сообщения должен осуществляться в send_msg до определения списка получателей. Но это чисто техническая сложность.
Идеологическая сложность в другом -- перехватчиков сообщений должно быть несколько и они должны выстраиваться в приоритетную схему. Какой должна быть данная схема? Например, при установке перехватчика сразу указывается его приоритет (как сейчас для события). Но что, если перехватчик с таким приоритетом уже есть?
Другой вопрос -- перехватчики иногда нужны для преобразования данных в сообщении "на лету". Например, отсылает кто-нибудь сообщение на проведение транзакции на сумму в N рублей, но в формате NрMк, а требуется получить в виде N.Mр. В дело вступает перехватчик, который преобразовывает сумму из одного формата в другой и дальше перемашрутизирует то же самое сообщение дальше. Вопрос здесь в том, чтобы модифицированное сообщение бесконечно не приходило в один и тот же перехватчик.
В mbapi такая штука возможна благодоря тому, что вместе с сообщением паредается т.н. расширенная информация, включающая в себя историю ремаршрутизации. И когда перехватчик ремаршрутизирует сообщение, то он обязан передать в функцию маршрутизации полную историю и собственное имя -- только тогда можно гарантировать, что сообщение не придет к нему обратно.
Собственно проблема в том, что я пока не решился на введение такого усложнения в текущую схему доставки сообщений. Поскольку фича несколько специфическая и не так уж часто используемая (по сравнению с обычной доставкой сообщений). А вот сам механизм усложнит изрядно.
E>>Возможность перехвата сообщений у нас сделана на основе отдельной библиотеки mbapi (message box api), которая построена поверх SObjectizer. Как раз там то, что ты описал и используется на полную катушку. И это действительно очень удобно и востребованно. Библиотека mbapi так же будет опубликована на SourceForge.
R>А на сколько она интегрируется с самим SObjectizer? R>Т.е. как бы это сказать, насколько агенты mbapi являются агентами SObjectizer и наоборот. Т.е. mbapi — это полная обёртка над SObjectizer, как MFC над WinAPI или приложение пишется на SObjectizer и mbapi охватывает только некоторые части...
Скорее она просто базируется на SObjectizer, как Qt может быть построена над WinAPI
Изначально в mbapi было введено понятие почтальона, который мог доставлять mbapi-сообщение тому или иному получателю. Не обязательно получателем должен был быть агент. Но самым простым и удобным способом в SObjectizer приложениях оказалось делать получателей сообщений агентами, а mbapi-сообщения доставлять получателю в виде обычного сообщения.
Выглядит это все, к примеру, таким образом:
/*
Демонстрационный агент, который периодически отсылает серверу сообщение
handshake_t и обрабатывает ответ от сервера в виде сообщения handshake_reply_t.
Типы handshake_t и handshake_reply_t -- это типы mbapi-сообщений.
*/class a_handshake_sender_t
: public so_4::rt::agent_t
{
typedef so_4::rt::agent_t base_type_t;
public :
// Преобразование mbapi-сообщения в сообщение агента.typedef mbapi_3::router::so_msg_templ_t<
mbapi_3::handshake_reply_t,
mbapi_3::mbox_dest_t,
mbapi_3::mbox_dest_t >
msg_handshake_reply;
a_handshake_sender_t(
const std::string & self_mbox_name )
: base_type_t( "a_handshake_sender" )
, m_self_mbox_name( self_mbox_name )
{
// Регистрация почтальона, который все время, пока данный агент
// зарегистрирован в SObjectizer, будет доставлять агенту
// mbapi-сообщения в виде msg_handshake_reply.
so_add_destroyable_traits(
new mbapi_3::router::so_msg_templ_postman_t<
msg_handshake_reply >(
// Явно задается имя агента и сообщения
// для последующего использования в send_msg.
so_query_name(), "msg_handshake_reply",
// Этот анализатор будет определять, что полученное
// handshake_reply_t действительно адресовано нам,
// а не кому-нибудь другому.
mbapi_3::router::dest_equality_analyzer(
mbapi_3::mbox_dest_t( self_mbox_name ) ) ) );
so_add_destroyable_traits(
new mbapi_3_mbox::core::auto_publish_traits_t(
self_mbox_name ) );
}
virtual const char *
so_query_type() const;
virtual void
so_on_subscription()
{
so_subscribe( "evt_tick", "msg_tick" );
so_subscribe( "evt_handshake_reply", "msg_handshake_reply" );
so_4::api::send_msg( so_query_name(), "msg_tick", 0, "",
3000, 3000 );
}
struct msg_tick {};
void
evt_tick()
{
// Вот так отсылаются mbapi-сообщения.
mbapi_3::router::route(
// Адрес получателя.
mbapi_3::mbox_dest_t( "server_box_1" ),
// Само тело сообщения.
mbapi_3::handshake_t(),
// Адрес оправителя. На этот адрес затем
// будет отсылаться ответ.
mbapi_3::mbox_dest_t( m_self_mbox_name ) );
}
void
evt_handshake_reply(
const msg_handshake_reply * cmd )
{
// Ответ получен, печатается имя его оправителя (т.е. сервера).
std::cout << "received handshake reply from: " << *(cmd->reply_to())
<< std::endl;
}
private :
std::string m_self_mbox_name;
};
Вообще говоря, мне бы хотелось видеть SObjectizer как максимально простое ядро, на которое дополнительная функциональность навешивается в виде дополнительных библиотек. Это можно видеть уже сейчас -- на SourceForge уже опубликованы SoAltChannel, который позволяет переключать каналы по резервным IP адресам, и SoSysConf, который позволяет собирать SObjectizer приложения как из конструктора. Ждут своей очереди к публикации, например, Generic Monitoring Tools (Gemont) для организации удаленного мониторинга SObjectizer приложений и mbapi для более сложных форм доставки и обработки сообщений.
Как бы повторяю ошибку Страуструпа -- зачем включать в ядро то, что можно поместить в библиотеки?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, remark, Вы писали:
R>Если у тебя до этого дойдут руки, то я, возможно, мог бы чем-нибудь посодействовать... R>Я имею в виду в плане lock-free структур данных.
Ok, спасибо. Буду, как говориться, держать в памяти.
Пользуясь случаем хочу, так сказать, прозондировать почву: как бы лично ты отнесся к появлению SObjectizer для D или, скажем, Scala?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Пользуясь случаем хочу, так сказать, прозондировать почву: как бы лично ты отнесся к появлению SObjectizer для D или, скажем, Scala?
Честно говоря, никак
Про D, конечно, слышал и видел код... если он станет промышленным языком, то другое дело, но это имхо пока сомнительно...
Про Scala аналогично...
А что опять стал вопрос портирования? Тут вроде уже обсуждалось и как бы вроде было такое мнение, что в большинстве других языком это не особо надо...
Где это, наверное, надо, так это как ни странно — С, но на него, наверное, печально портировать с С++
Здравствуйте, eao197, Вы писали:
E>Возможно, этого же можно достичь на прикладном уровне, введя некоторый базовый тип msg_with_request_id_t, в котором будет содержаться информация для отсылки ответа. И вспомогательный метод/свободную функцию answer_for, которая получив наследника msg_with_request_id_t сама выполняет отсылку ответного сообщения.
А... ну это собственно тоже решение.
Можно и в виде расширений и надстроек, главное, что бы эти надстройки можно было реализовать поверх. Вот, например, сразу возник вопрос, а сообщение может само своё удаление отложить? Насколько я помню, сейчас фремворк управляет временем жизни сообщений...
... E>Собственно проблема в том, что я пока не решился на введение такого усложнения в текущую схему доставки сообщений. Поскольку фича несколько специфическая и не так уж часто используемая (по сравнению с обычной доставкой сообщений). А вот сам механизм усложнит изрядно.
Ясно.
E>Вообще говоря, мне бы хотелось видеть SObjectizer как максимально простое ядро, на которое дополнительная функциональность навешивается в виде дополнительных библиотек. Это можно видеть уже сейчас -- на SourceForge уже опубликованы SoAltChannel, который позволяет переключать каналы по резервным IP адресам, и SoSysConf, который позволяет собирать SObjectizer приложения как из конструктора. Ждут своей очереди к публикации, например, Generic Monitoring Tools (Gemont) для организации удаленного мониторинга SObjectizer приложений и mbapi для более сложных форм доставки и обработки сообщений.
E>Как бы повторяю ошибку Страуструпа -- зачем включать в ядро то, что можно поместить в библиотеки?
Опять же опять всё упирается в то, насколько фреймворк предоставляет возможности для расширения и хуки...
Но в целом, я понял...
Здравствуйте, remark, Вы писали:
R>Про D, конечно, слышал и видел код... если он станет промышленным языком, то другое дело, но это имхо пока сомнительно... R>Про Scala аналогично...
А сейчас что с D, что со Scala ситуация такая -- сами по себе промышленными языками они не станут, их можно только таковыми сделать
R>А что опять стал вопрос портирования? Тут вроде уже обсуждалось и как бы вроде было такое мнение, что в большинстве других языком это не особо надо...
Вопрос потрирования никто и не снимал Да и речь шла о других языках, на которых биты из тактов не выжимают, а XML-ями направо и налево размениваются
Просто в все упирается в простой факт: чем дальше, тем дороже обходится развитие C++ проектов -- новых людей приходится C++у с нуля учить, да и без особого энтузиазма он изучается
А более современными языками пользоваться приятнее, есть надежда, что и новых людей им обучать будет проще.
R>Где это, наверное, надо, так это как ни странно — С, но на него, наверное, печально портировать с С++
Не, это уже без меня Я слишком OOP addicted man.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Про D, конечно, слышал и видел код... если он станет промышленным языком, то другое дело, но это имхо пока сомнительно... R>>Про Scala аналогично...
E>А сейчас что с D, что со Scala ситуация такая -- сами по себе промышленными языками они не станут, их можно только таковыми сделать
Ну так скажем, а мои ближайшие планы не входит продвигать какой-либо язык в ранг промышленных
Может быть как-нить потом...
R>>А что опять стал вопрос портирования? Тут вроде уже обсуждалось и как бы вроде было такое мнение, что в большинстве других языком это не особо надо...
E>Вопрос потрирования никто и не снимал Да и речь шла о других языках, на которых биты из тактов не выжимают, а XML-ями направо и налево размениваются E>Просто в все упирается в простой факт: чем дальше, тем дороже обходится развитие C++ проектов -- новых людей приходится C++у с нуля учить, да и без особого энтузиазма он изучается E>А более современными языками пользоваться приятнее, есть надежда, что и новых людей им обучать будет проще.
Ну фиг знает — время расставит точки...
Идея простого промышленного языка — имхо фикция...
В сложности современных систем язык является величиной меньшего порядка малости... опять же имхо... ну ладно, с этим уже надо идти в Философию
R>>Где это, наверное, надо, так это как ни странно — С, но на него, наверное, печально портировать с С++
E>Не, это уже без меня Я слишком OOP addicted man.
А что мешает на С OOP применять?
Вроде недавно в С/С++ проскакивала ссылка на книгу типа "ООП на С"
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Если у тебя до этого дойдут руки, то я, возможно, мог бы чем-нибудь посодействовать... R>>Я имею в виду в плане lock-free структур данных.
E>Ok, спасибо. Буду, как говориться, держать в памяти.
А это сейчас в каком статусе? Я так понимаю в статусе просто идеи. Или уже чётко решено, что в ближайшие месяцы надо ещё повышать производительность?
А какие структуры сейчас являются узким местом?
Могу предположить, что, естественно, fifo очереди для сообщений. Так же скорее всего какие-нибудь "глобальные" данные, типа настроек или кэшей. Возможно какие-то lifo стеки. Скорее всего ещё какие-нибудь отображения hash/map... Что-то ещё?
Здравствуйте, remark, Вы писали:
R>>>Если у тебя до этого дойдут руки, то я, возможно, мог бы чем-нибудь посодействовать... R>>>Я имею в виду в плане lock-free структур данных.
E>>Ok, спасибо. Буду, как говориться, держать в памяти.
R>А это сейчас в каком статусе? Я так понимаю в статусе просто идеи. Или уже чётко решено, что в ближайшие месяцы надо ещё повышать производительность?
Нет, пока понятно, что в версию 4.4 реализация на основе lock-free алгоритмов не попадет. Сейчас задача в том, чтобы повышать производительность сетевых обменов, но не отсылки сообщений внутри SObjectizer.
R>А какие структуры сейчас являются узким местом? R>Могу предположить, что, естественно, fifo очереди для сообщений. Так же скорее всего какие-нибудь "глобальные" данные, типа настроек или кэшей. Возможно какие-то lifo стеки. Скорее всего ещё какие-нибудь отображения hash/map... Что-то ещё?
Нет, узким местом являются не структуры. А счетчики ссылок на экземпляры сообщений и агентов. Без этих счетчиков нельзя точно определять моменты удаления сообщений и дерегистрации агентов. А для корректного изменения счетчиков требуется синхронизация на mutex-е, именно она все и тормозит. Причем сейчас не представляется возможным использовать Interlocked-операции инкремента и декремента.
В какой-то момент времени возникла идея, что если для сообщения проверять не счетчик ссылок, а хвост списка необработанных заявок (а сам список как раз является look-free очередью), то не нужно синхронизация для проверки того, что список пуст.
Кстати из-за всех этих счетчиков так же есть подозрение, что часть операций могла бы быть реализована в SObjectizer более просто, и работать быстрее, при использовании языка со сборкой мусора. Отсюда и интерес к D.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
R>>А какие структуры сейчас являются узким местом? R>>Могу предположить, что, естественно, fifo очереди для сообщений. Так же скорее всего какие-нибудь "глобальные" данные, типа настроек или кэшей. Возможно какие-то lifo стеки. Скорее всего ещё какие-нибудь отображения hash/map... Что-то ещё?
E>Нет, узким местом являются не структуры. А счетчики ссылок на экземпляры сообщений и агентов. Без этих счетчиков нельзя точно определять моменты удаления сообщений и дерегистрации агентов. А для корректного изменения счетчиков требуется синхронизация на mutex-е, именно она все и тормозит. Причем сейчас не представляется возможным использовать Interlocked-операции инкремента и декремента.
Хм... а почему нельзя использовать Interlocked-операции?
E>В какой-то момент времени возникла идея, что если для сообщения проверять не счетчик ссылок, а хвост списка необработанных заявок (а сам список как раз является look-free очередью), то не нужно синхронизация для проверки того, что список пуст.
Интересно...
E>Кстати из-за всех этих счетчиков так же есть подозрение, что часть операций могла бы быть реализована в SObjectizer более просто, и работать быстрее, при использовании языка со сборкой мусора. Отсюда и интерес к D.
Сборка мусора — это тоже не панацея — там своих проблем хватает...
Здравствуйте, remark, Вы писали:
E>>Нет, узким местом являются не структуры. А счетчики ссылок на экземпляры сообщений и агентов. Без этих счетчиков нельзя точно определять моменты удаления сообщений и дерегистрации агентов. А для корректного изменения счетчиков требуется синхронизация на mutex-е, именно она все и тормозит. Причем сейчас не представляется возможным использовать Interlocked-операции инкремента и декремента.
R>Хм... а почему нельзя использовать Interlocked-операции?
Потому что изменение счетчика ссылок на сообщение должно выполняться в одной же транзакции с изменением счетчика ссылок на агента-владельца. А иногда и еще какой-то счетчик задействуется (если не забыл ничего). Т.е. за раз нужно изменять сразу несколько ссылок.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, remark, Вы писали:
E>>>Нет, узким местом являются не структуры. А счетчики ссылок на экземпляры сообщений и агентов. Без этих счетчиков нельзя точно определять моменты удаления сообщений и дерегистрации агентов. А для корректного изменения счетчиков требуется синхронизация на mutex-е, именно она все и тормозит. Причем сейчас не представляется возможным использовать Interlocked-операции инкремента и декремента.
R>>Хм... а почему нельзя использовать Interlocked-операции?
E>Потому что изменение счетчика ссылок на сообщение должно выполняться в одной же транзакции с изменением счетчика ссылок на агента-владельца. А иногда и еще какой-то счетчик задействуется (если не забыл ничего). Т.е. за раз нужно изменять сразу несколько ссылок.
А почему это должно быть именно в одной транзакции? Почему никто не должен видеть эти счётчики в рассогласованных состояниях? Ведь с reference counting'ом обычно так — или в счётчике не ноль и тогда собственно пофигу что, т.к. объект не удаляется, или в счётчике 0, и тогда вобщем-то тоже пофигу, т.к. объект удаляется...
Здравствуйте, remark, Вы писали:
E>>Потому что изменение счетчика ссылок на сообщение должно выполняться в одной же транзакции с изменением счетчика ссылок на агента-владельца. А иногда и еще какой-то счетчик задействуется (если не забыл ничего). Т.е. за раз нужно изменять сразу несколько ссылок.
R>А почему это должно быть именно в одной транзакции? Почему никто не должен видеть эти счётчики в рассогласованных состояниях? Ведь с reference counting'ом обычно так — или в счётчике не ноль и тогда собственно пофигу что, т.к. объект не удаляется, или в счётчике 0, и тогда вобщем-то тоже пофигу, т.к. объект удаляется...
Интересно, нужно будет об этом подумать.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, remark, Вы писали:
R>>>Хм... а почему нельзя использовать Interlocked-операции?
E>>Потому что изменение счетчика ссылок на сообщение должно выполняться в одной же транзакции с изменением счетчика ссылок на агента-владельца. А иногда и еще какой-то счетчик задействуется (если не забыл ничего). Т.е. за раз нужно изменять сразу несколько ссылок.
R>А почему это должно быть именно в одной транзакции? Почему никто не должен видеть эти счётчики в рассогласованных состояниях? Ведь с reference counting'ом обычно так — или в счётчике не ноль и тогда собственно пофигу что, т.к. объект не удаляется, или в счётчике 0, и тогда вобщем-то тоже пофигу, т.к. объект удаляется...
Я тут сваял тестик с некоторой имитацией подсчета ссылок в SObjectizer. Он делает подсчет ссылок на основе блокировке на mutex-е (фактически, critical section в Windows) и на основе atomic-операций. Дело в том, что в SObjectizer нужно увеличивать не один счетчик, а четыре. Поэтому интересно было сравнить, насколько четыре atomic-op выгоднее, чем один mutex. Оказались, что не выгоднее.
Вот замеры на Pentium-M 1.5GHz (512Mb, WinXP-SP2):
На двух-процессорной машине при увеличении количества нитей вариант на atomic-op проигрывает гораздо больше варианту с mutex-ом, чем на однопроцессорной (разрыв больше).
У тебя есть возможность прогнать этот тест на 4-х процессорной машине? (А то в моем распоряжении только 2-х процессорные). Требуется ACE, я использовал ACE 5.5.6.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Я тут сваял тестик с некоторой имитацией подсчета ссылок в SObjectizer. Он делает подсчет ссылок на основе блокировке на mutex-е (фактически, critical section в Windows) и на основе atomic-операций. Дело в том, что в SObjectizer нужно увеличивать не один счетчик, а четыре. Поэтому интересно было сравнить, насколько четыре atomic-op выгоднее, чем один mutex. Оказались, что не выгоднее.
В принципе это достаточно ожидаемый результат, т.к. основной вклад в стоимость операций вносят atomic операции.
При использовании мьютекса это 2 операции. При использовании reference counting на atomic операциях это соотв. 4...
E>На двух-процессорной машине при увеличении количества нитей вариант на atomic-op проигрывает гораздо больше варианту с mutex-ом, чем на однопроцессорной (разрыв больше).
По той же причине...
E>У тебя есть возможность прогнать этот тест на 4-х процессорной машине? (А то в моем распоряжении только 2-х процессорные). Требуется ACE, я использовал ACE 5.5.6.
Нет, 4-ёх ядерной у меня нет...
А тебя в SObjectizer мьютексы тоже локальные используются или один глобальный? Если один глобальный, то в тесте надо тоже сделать один на все объекты, а не на каждый объект по мьютексу...
А сколько в SObjectizer в среднем за один раз счётчиков изменяется? Может меньше 4? Если сделать тест с 2 или 3 счётчиками, то результаты тоже должны поменяться...
Ну в принципе, что я могу сказать... надо смотреть конкретную ситуацию... в общем случае задача — уменьшать кол-во atomic операций, уменьшать кол-во барьеров памяти, уменьшать конкуренцию на кэш-линии, уменьшать доступ к глобальным данным и т.д.
Вот так-вот просто заменить — ничего хорошего не получится. К сожалению, сейчас в сети множество таких "lock-free" алгоритмов, для которых требуется по 5-6 atomic операций — конечно они убивают всё производительность на корню.
Ситуация такая: при использовании мьютексов всё жестко определено — у тебя будет 2 atomic операции + возможность очень дорогой блокировки. при использовании lock-free ничего не детерминировано — ты можешь сделать очень плохой алгоритм, можешь сделать такой же как на мьютексах, можешь при определённом везении и знании сделать в конкретной ситуации алгоритм, который будет летать — иметь 0 atomic операций, не обращаться к глобальным данным, масштабироваться линейно и т.д... но это в любом случае будет кровавый поединок человека и машины
Что можно делать: амортизировать кол-во дорогих операций (добавлять thread-local кэши, выполнять дорогие операции не каждый раз и т.д.), локализовать данные (делать данные по возможности thread-local, или one-thread-write), локализовывать потоки по процессорам, добавлять короткие пути для типовых ситуаций, группировать счётчики референсов и т.д. и т.п.
Простор широчайший, а что делать конкретно — надо смотреть конкретную ситуацию...
А в коде этот референс каунтинг локализован? Я смогу более-менее быстро окинуть его взглядом? Можешь скажешь куда смотреть.
Или может даже лучше ты как-то обрисуешь в общих чертах, что там происходит? Ну я так понимаю, что естественно для сообщений есть счётчик, устанавливается он при отправке сообщений, и уменьшается при обработке каждым агентом. Так? А ещё с чем связаны счётчики? С агентами? А когда они изменяются? Откуда берётся 4 счётчика?
Здравствуйте, remark, Вы писали:
R>А тебя в SObjectizer мьютексы тоже локальные используются или один глобальный? Если один глобальный, то в тесте надо тоже сделать один на все объекты, а не на каждый объект по мьютексу...
Глобальные мьютексы используются (если вспоминать навскидку) для:
* защиты ядра SObjectizer и его системного словаря при выполнении таких операций, как send_msg, register_coop, deregister_coop и пр.;
* при выделении памяти в стандратной библиотеке C++.
Остальные же мьютексы сделаны так: на каждый класс агентов заводится собственный мьютекс. Захват этого мьютекса выполнятся только при работе с агентами этого типа, его сообщениями или его событиями.
R>А сколько в SObjectizer в среднем за один раз счётчиков изменяется? Может меньше 4? Если сделать тест с 2 или 3 счётчиками, то результаты тоже должны поменяться...
Думаю, что таки не меньше 4-х:
* один счетчик для агента;
* один счетчик для сообщения;
* один счетчик для события;
* счетчики для сообщений и событий инкрементируются и декрементируются при помещении некоторых объектов в некоторые контейнеры (см. ниже).
R>Ситуация такая: при использовании мьютексов всё жестко определено — у тебя будет 2 atomic операции + возможность очень дорогой блокировки. при использовании lock-free ничего не детерминировано — ты можешь сделать очень плохой алгоритм, можешь сделать такой же как на мьютексах, можешь при определённом везении и знании сделать в конкретной ситуации алгоритм, который будет летать — иметь 0 atomic операций, не обращаться к глобальным данным, масштабироваться линейно и т.д... но это в любом случае будет кровавый поединок человека и машины
Я бы добавил сюда еще и потенциальные проблемы с переносимостью atomic-операций. На x86 есть инструкции для их поддержке. А вот на каких-нибудь Sun-ах или MIPS-ах с этим дело как обстоит?
R>А в коде этот референс каунтинг локализован? Я смогу более-менее быстро окинуть его взглядом? Можешь скажешь куда смотреть. R>Или может даже лучше ты как-то обрисуешь в общих чертах, что там происходит? Ну я так понимаю, что естественно для сообщений есть счётчик, устанавливается он при отправке сообщений, и уменьшается при обработке каждым агентом. Так? А ещё с чем связаны счётчики? С агентами? А когда они изменяются? Откуда берётся 4 счётчика?
Принцип такой:
* при отсылке сообщения создается объект so_4::rt::msg_data_t. Он создает объект so_4::rt::impl::msg_data_impl_t;
* когда создается объект so_4::rt::impl::msg_data_impl_t (т.е. описатель экземпляра сообщения внутри SObjectizer), то увеличивается счетчик ссылок на сам msg_data_impl_t, а так же на соответствующего агента (объект so_4::rt::impl::agent_wrapper_base_t);
* при копировании so_4::rt::msg_data_t инкрементируются и декрементируются счетчики на so_4::rt::impl::msg_data_impl_t;
* при диспетчеризации заявок, полученных при отсылке сообщения, создаются объекты so_4::rt::event_data_t. Которые содержат в себе объекты, производные от so_4::rt::impl::event_data_impl_t;
* когда создается объект so_4::rt::impl::evt_data_impl_t (т.е. описатель одной заявки для события), то увеличивается счетчик ссылок на сам evt_data_impl_t и на соответствующего агента;
* так же so_4::rt::impl::evt_data_impl_t содежат ссылку на msg_data_impl_t и для сохранения ее корректности увеличивают количество ссылок на msg_data_impl_t (с соответствующим увеличением количества ссылок на агента).
Схема запутанная, но пять лет назад я не смог придумать ничего лучше, поскольку объекты msg_data_t, event_data_t всю эту кухню скрывают внутри себя, что позволяет легко манипулировать объектами msg_data_t, event_data_t -- а это было очень важно чтобы получить корректно работающую версию SObjectizer.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Принцип такой: E>* при отсылке сообщения создается объект so_4::rt::msg_data_t. Он создает объект so_4::rt::impl::msg_data_impl_t; E>* когда создается объект so_4::rt::impl::msg_data_impl_t (т.е. описатель экземпляра сообщения внутри SObjectizer), то увеличивается счетчик ссылок на сам msg_data_impl_t, а так же на соответствующего агента (объект so_4::rt::impl::agent_wrapper_base_t); E>* при копировании so_4::rt::msg_data_t инкрементируются и декрементируются счетчики на so_4::rt::impl::msg_data_impl_t; E>* при диспетчеризации заявок, полученных при отсылке сообщения, создаются объекты so_4::rt::event_data_t. Которые содержат в себе объекты, производные от so_4::rt::impl::event_data_impl_t; E>* когда создается объект so_4::rt::impl::evt_data_impl_t (т.е. описатель одной заявки для события), то увеличивается счетчик ссылок на сам evt_data_impl_t и на соответствующего агента; E>* так же so_4::rt::impl::evt_data_impl_t содежат ссылку на msg_data_impl_t и для сохранения ее корректности увеличивают количество ссылок на msg_data_impl_t (с соответствующим увеличением количества ссылок на агента).
Я правильно понимаю ситуацию, что увеличение/уменьшение референса для агента при создании/удалении сообщений и событий необходимо, что бы агент не умер пока существуют его сообщения и события?
При этом агент держит сам на себя один референс, и удаляет его, когда пользователь говорит удалить агента. При этом агент может просуществовать немного дольше — пока живут его сообщения и события?
Соответственно увеличение/уменьшение референса для сообщений при создании/удалении событий необходимо, что бы сообщение не умерло пока не обработаны все связанные с ним события?
Здравствуйте, remark, Вы писали:
R>Я правильно понимаю ситуацию, что увеличение/уменьшение референса для агента при создании/удалении сообщений и событий необходимо, что бы агент не умер пока существуют его сообщения и события?
Да.
R>При этом агент держит сам на себя один референс, и удаляет его, когда пользователь говорит удалить агента. При этом агент может просуществовать немного дольше — пока живут его сообщения и события?
Агент на себя не держит референса. Если счетчик ссылок у агента равен нулю, то агент может быть сразу же дерегистрирован. Если счетчик ссылок на агента отличен от нуля, то агент будет жить пока этот счетчик не обнулится.
R>Соответственно увеличение/уменьшение референса для сообщений при создании/удалении событий необходимо, что бы сообщение не умерло пока не обработаны все связанные с ним события?
Да. С самими событиями аналогичная ситуация -- событие не должно исчезнуть, пока оно хоть кем-то используется (например, стоит в очереди диспетчера или уже обрабатывается агентом).
SObjectizer: <микро>Агентно-ориентированное программирование на C++.