Я перестраиваю систему обмена сообщениями для моего приложения, чтобы использовать строительные блоки Intel Threading, и я тупо пытаюсь сделать выбор между двумя возможными подходами.
По сути, у меня есть последовательность объектов сообщений и для каждого типа сообщений,последовательность обработчиков.Для каждого объекта сообщения я применяю каждый обработчик, зарегистрированный для этого типа объектов сообщения.
Последовательная версия будет выглядеть примерно так (псевдокод):
for each message in message_sequence <- SEQUENTIAL
for each handler in (handler_table for message.type)
apply handler to message <- SEQUENTIAL
Первый подход , который я рассматриваю, обрабатывает объекты сообщений по очереди (последовательно) и одновременно применяет обработчики.
Плюсы:
- предсказуемое упорядочение сообщений (т.е.нам гарантирован порядок обработки FIFO)
- (потенциально) меньшая задержка обработки каждого сообщения
Минусы:
- больше ресурсов обработки доступно, чем обработчиковдля одного типа сообщений (плохое распараллеливание)
- неправильное использование кэша процессора, поскольку объекты сообщений необходимо копировать для каждого обработчика, чтобы использовать
- большие издержки для маленьких обработчиков
Псевдокод этого подхода будет выглядеть следующим образом:
for each message in message_sequence <- SEQUENTIAL
parallel_for each handler in (handler_table for message.type)
apply handler to message <- PARALLEL
Второй подход заключается в обработке сообщений параллельноl и применять обработчики к каждому сообщению последовательно.
Плюсы:
- лучшее использование кэша процессора (сохраняет объект сообщения локальным для всех обработчиков, которые будут его использовать)
- небольшие обработчики не накладывают столько накладных расходов (при условии, что должны быть запущены и другие обработчики)
- ожидается больше сообщений, чем имеется обработчиков, поэтому вероятность параллелизма выше
Минусы:
- Непредсказуемый порядок - если сообщение A отправляется до сообщения B, они могут обрабатываться одновременно или B может завершить обработку до завершения всех обработчиков A(порядок недетерминирован)
Псевдокод выглядит следующим образом:
parallel_for each message in message_sequence <- PARALLEL
for each handler in (handler_table for message.type)
apply handler to message <- SEQUENTIAL
Второй подход имеет больше преимуществ, чем первый, но недетерминированный порядокбольшой недостаток ..
Какой подход вы бы выбрали и почему?Есть ли какие-то другие подходы, которые я должен рассмотреть (кроме очевидного третьего подхода: параллельные сообщения и параллельные обработчики, которые, насколько я могу судить, имеют недостатки обоих и не имеют реальных факторов выкупа)?
Спасибо!
РЕДАКТИРОВАТЬ:
Я думаю, что я буду делать, это использовать # 2 по умолчанию, но разрешить "тег разговора", который будет прикреплен к каждому сообщению.Любые сообщения с одним и тем же тегом упорядочиваются и обрабатываются последовательно по отношению к его разговору.Обработчики передают тег беседы вместе с сообщением, поэтому они могут продолжить диалог, если они этого требуют.Примерно так:
Conversation c = new_conversation()
send_message(a, c)
...
send_message(b, c)
...
send_message(x)
handler foo (msg, conv)
send_message(z, c)
...
register_handler(foo, a.type)
a обрабатывается до b, что обрабатывается до z.x может обрабатываться параллельно с a, b и z.Как только все сообщения в беседе обработаны, беседа уничтожается.