Варианты системы передачи сообщений для игры

Я работаю над игрой RTS на C++, ориентированной на портативное оборудование (Pandora). Для справки, Pandora имеет один процессор ARM с частотой ~ 600 МГц и работает под управлением Linux. Мы пытаемся установить хорошую систему передачи сообщений (как внутреннюю, так и внешнюю), и для меня это новая территория.

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

sendMessage("model-loader", "load-model", my_model.path, model_id );

Взамен модуль может ожидать какое-то сообщение, содержащее объект модели для конкретного model_id, которое затем может быть передано в графическую систему. Обратите внимание, что эта функция sendMessage никоим образом не является окончательной. Это просто отражает мое текущее понимание систем передачи сообщений, что, вероятно, неверно :)

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

Другой вариант — полностью пройти сетевой уровень. У этого есть некоторые забавные преимущества, такие как асинхронная передача сообщений практически бесплатно. Кроме того, мы получаем возможность передавать сообщения другим машинам, используя те же вызовы, что и при передаче локально. Однако это решение меня не устраивает, вероятно, потому, что я не совсем его понимаю :) Нужен ли нам сокет для каждого объекта, который будет отправлять/получать сообщения? Если да, то это кажется чрезмерным. В данной игре будут тысячи объектов. Я опасаюсь, что для такого маломощного устройства, как Pandora, такое злоупотребление сетью может стать нашим узким местом. Но я еще не проводил никаких тестов, так что это только предположение.

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

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


person sinoth    schedule 16.06.2009    source источник


Ответы (3)


Сеть также будет использовать блокировку. Просто он будет там, где его не видно, в ядре ОС.

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

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

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

person Zan Lynx    schedule 16.06.2009
comment
Согласен, с оговоркой, что вы должны начать с реализации самого простого подхода (возможно, сетевого) и беспокоиться о перекодировании только для скорости, если позднее профилирование покажет, что вам это нужно. - person T.E.D.; 16.06.2009

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

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

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

person T.E.D.    schedule 16.06.2009

Я согласен с рекомендацией Зана по возможности передавать сообщения в память.

Одна из причин заключается в том, что вы можете передавать сложные объекты C++ без необходимости их маршалирования и демаршалирования (сериализации и десериализации).

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

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

person Bruno Rijsman    schedule 16.06.2009