В Cap'n Proto вы должны , а не повторно использовать MessageBuilder
для нескольких сообщений. То, как вы написали свой код, каждая итерация вашего l oop сделает сообщение больше, потому что вы фактически добавляете к существующему сообщению, а не начинаете новое. Чтобы избежать выделения памяти при каждой итерации, вы должны передать рабочий буфер в конструктор MallocMessageBuilder
. Чистый буфер может быть выделен один раз за пределами l oop, но вам нужно каждый раз создавать новый MallocMessageBuilder
вокруг l oop. (Конечно, большинство людей не заботятся о чистых буферах и просто позволяют MallocMessageBuilder
делать свое собственное распределение, но если вы выберете этот путь в этом тесте, вам также следует изменить тест Protobuf, чтобы создать новый объект сообщения для каждого итерация, а не повторное использование одного объекта.)
Кроме того, ваш код Cap'n Proto использует capnp::messageToFlatArray()
, который выделяет новый буфер для размещения сообщения и копирует все сообщение. Это не самый эффективный способ использования Cap'n Proto. Обычно, если вы записывали сообщение в файл или сокет, вы писали бы напрямую из исходного резервного буфера (ов) сообщения, не создавая эту копию. Попробуйте сделать это вместо этого:
kj::ArrayPtr<const kj::ArrayPtr<const capnp::word>> segments =
message_builder.getSegmentsForOutput();
// Send segments
// Receive segments
capnp::SegmentArrayMessageReader message_receiver_builder(segments);
Или, чтобы сделать вещи более реалистичными c, вы можете записать сообщение в канал и прочитать его обратно, используя capnp::writeMessageToFd()
и capnp::StreamFdMessageReader
. (Чтобы быть справедливым, вам нужно было бы сделать так, чтобы тестовый протокол protobuf также записывал / читал из канала.)
(я являюсь автором Cap'n Proto и Protobuf v2. Я не знаком с FlatBuffers, поэтому я не могу комментировать, есть ли в этом коде аналогичные проблемы ...)
О тестах
Я потратил много времени на тестирование Protobuf и Cap ' Прото. Одна вещь, которую я узнал в процессе, состоит в том, что самые простые тесты, которые вы можете создать, не дадут вам реалистичных c результатов.
Во-первых, любой формат сериализации (даже JSON) может "выиграть", учитывая Правильный эталонный случай. Различные форматы будут работать очень и очень по-разному в зависимости от контента. Является ли он строковым, числовым или объектным (то есть с глубокими деревьями сообщений)? Разные форматы здесь имеют разные сильные стороны (например, Cap'n Proto невероятно хорош в числах, потому что он их вообще не трансформирует; JSON невероятно плох в них). Ваш размер сообщения невероятно короткий, средний или очень большой? Короткие сообщения будут в основном использовать код настройки / разрыва, а не обработку тела (но настройка / разборка важна - иногда в реальных случаях использования используется много небольших сообщений!). Очень большие сообщения разрушат кэш L1 / L2 / L3 и расскажут вам больше о пропускной способности памяти, чем сложности анализа (но, опять же, это важно - некоторые реализации более дружественны к кешам, чем другие).
Даже после Учитывая все это, у вас есть еще одна проблема: запуск кода в al oop фактически не говорит вам, как он работает в реальном мире. При работе в узком l oop кэш команд остается горячим, и все ветви становятся очень предсказуемыми. Таким образом, для сериализации с интенсивным ветвлением (например, protobuf) стоимость ветвления будет ограничена, и сериализация с большим объемом кода (опять-таки ... как protobuf) также получит преимущество. Вот почему микро-тесты действительно полезны только для сравнения кода с другими его версиями (например, для тестирования незначительных оптимизаций), а НЕ для сравнения совершенно разных кодовых баз друг с другом. Чтобы выяснить, как все это работает в реальном мире, вам необходимо измерить пример использования в реальном времени. Но ... честно говоря, это довольно сложно. Мало кто успевает построить две версии своего приложения на основе двух разных сериализаций, чтобы узнать, какая из них выиграет ...