Тема была начата двумя сообщениями: "Агент-collector + агент-performer = паттерн для нескольких ситуаций" и "Еще одна идея по балансировке нагрузки на нескольких агентов". Изложенные в вышеозначенных постах идеи удалось проиллюстрировать небольшими работающими примерами. Они уже есть в репозитории SObjectizer-а на SourceForge: collector_performer_pair и collector_many_performers, пока в branches, но во время следующего релиза обязательно войдут в стабильную версию.
При написании примеров выяснилось, что распараллелить обработку сообщений посредством thread_safe-событий и диспетчера adv_thread_pool очень просто, все делается буквально по щелчку. А вот с идеей реализации агентов-близнецов дело не пошло.
При попытке продумать реализацию механизмов работы агентов-близнецов стало обнаруживаться слишком много подводных камней. А при поиске альтернатив оказалось, что того же самого можно достичь и посредством уже имеющихся средств SObjectizer-а. Что и демонстрируется в примере collector_many_performers.
Весь фокус оказался в том, чтобы создать N совершенно обычных агентов-performer-ов, имеющих свои собственные multi-producer/single-consumer почтовые ящики (их еще называют direct-mbox-ы). Эти агенты привязываются к обычному thread_pool-диспетчеру (в этом случае разумно, чтобы у диспетчера было N рабочих нитей). Когда агент-performer свободен, он отсылает агенту-collector-у сообщение select_next_job в котором сообщает collector-у свой direct-mbox.
Агенту-collector-у остается только вести очередь свободных mbox-ов агентов-performer-ов и при появлении новой заявки просто пересылать ее на первый mbox из этой очереди. Когда очередь свободных mbox-ов пуста, а заявки поступают, то заявки складываются в промежуточный буфер ограниченного размера. И извлекаются оттуда как только появляется первый свободный performer.
В общем, оказалось, что не нужно выдумывать велосипеды и усложнять ядро SObjectizer новыми сущностями. Многое можно делать уже на том, что есть.
А вот над чем еще имеет смысл подумать при подготовке следующей версии -- так это о поддержке "приватных диспетчеров". Т.е. диспетчеров, которые создаются для нужд конкретной кооперации и удаляются как только кооперация завершает свою работу. В двух новых примерах именно это и происходит: создается несколько рабочих коопераций, в которые входит один агент-collector и либо один агент-performer (пример collector_performer_pair), либо группа агентов-performer-ов (пример collector_many_peformers). Агенты-collector-ы всех рабочих коопераций работают на общем thread_pool-диспетчере, который создается при старте SObjectizer. А вот для агентов-performer-ов создаются собственные диспетчеры. Если рабочая кооперация дерегистрируется, то в настоящем SObjectizer-е диспетчер для этой кооперации останется. Для данного примера это вполне нормально, но вообще-то было бы лучше сделать так, чтобы приватный диспетчер дерегистрированной кооперации так же прекратил свою работу.
PS. Оба новых примера являются переработанными вариантами примера реализации механизма producer-consumer, который я более подробно разбирал в конце октября 2014.
PPS. Поймал себя на интересном наблюдении. Давно ничего не писал на SObjectizer, все больше колупался в его внутренностях. Но при написании новых примеров (точнее при переделке старого примера на новые лады) оказалось, что принятая в SObjectizer форма представления агентов -- в виде экземпляров классов-наследников so_5::rt::agent_t с оформлением обработчиков событий в виде методов, со специальными методами so_define_agent и so_evt_start, -- это весьма удобно. Сразу знаешь, где что смотреть и где чего вписывать: подписка на сообщения вот здесь, стартовые действия вот здесь, конкретные операции вот здесь. Очень неожиданное и приятное открытие. Признаться, при сравнении SObjectizer с аналогичными разработками заработал себе некоторый комплекс из-за большего "синтаксического оверхеда" (c) SObjectizer-а. А тут выясняется, что разумная многословность и ранее принятые соглашения об оформлении классов агентов -- это не зло, а благо :) Пустячок, а приятно. В связи с чем хочу выразить отдельную благодарность Николаю Гродзицкому, который уже давно указывал мне на это, и регулярно одергивал меня при попытках что-либо кардинально изменить в этом направлении :)
Комментариев нет:
Отправить комментарий