Как подойти к параллельной обработке сообщений? - PullRequest
2 голосов
/ 13 июня 2010

Я перестраиваю систему обмена сообщениями для моего приложения, чтобы использовать строительные блоки 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.Как только все сообщения в беседе обработаны, беседа уничтожается.

Ответы [ 4 ]

2 голосов
/ 13 июня 2010

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

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

Это может быть сделано с очень небольшими накладными расходами синхронизации - возможно, только с атомарными операциями, без тяжелых примитивовнапример, мьютексы или семафоры.

Кроме того, если вы передаете сообщение каждому обработчику по ссылке , вместо того, чтобы делать копию, одно и то же сообщение обрабатывается одновременно разными обработчиками на разных ядрах ЦП.на самом деле улучшает производительность кэша, поскольку более высокие уровни кэша (обычно от L2 и выше) часто совместно используются между ядрами ЦП - поэтому, когда один обработчик считывает сообщение в кэш, другой обрабатываетвторое ядро ​​будет иметь это сообщение уже в L2.Так что подумайте - вам действительно нужно копировать сообщения?

1 голос
/ 13 июня 2010

Полагаю, все сводится к тому, важен ли порядок.Если порядок не важен, вы можете перейти к методу 2. Если порядок важен, вы перейдете к методу 1. В зависимости от того, что должно делать ваше приложение, вы все равно можете перейти к методу 2, но использовать порядковый номер, чтобы все сообщенияобрабатываются в правильном порядке (если нет причины, если вы пытаетесь оптимизировать часть обработки).

1 голос
/ 13 июня 2010

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

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

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

0 голосов
/ 13 июня 2010

Первый метод также имеет непредсказуемый порядок.Обработка сообщения 1 в потоке 1 может занять очень много времени, что делает возможным, что сообщения 2, 3 и 4 уже давно обработаны

. Это приведет к снижению баланса до метода 2

Редактировать: Iпосмотрим, что вы имеете в виду.

Однако, почему в методе 2 вы будете делать обработчики последовательно.В методе 1 порядок не имеет значения, и с этим у вас все в порядке.

Например, метод 3: обрабатывать сообщения и обработчики параллельно.

Конечно, и здесь порядок не гарантирован.

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

...