Быстрое двоичное кодирование позволяет описывать любые доменные модели, бизнес -объекты, сложные структуры данных, запросы и ответы клиента/сервер и генерировать собственный код для различных языков и платформ программирования.
Быстрая бинарная документация кодирования
Быстрое двоичное кодирование загрузки
Спецификация быстрого двоичного кодирования
Сравнение производительности с другими протоколами можно найти здесь:
| Протокол | Размер сообщения | Время сериализации | Время деессериализации |
|---|---|---|---|
| Cap'n'proto | 208 байтов | 558 нс | 359 нс |
| FastbinaryCoding | 234 байта | 66 нс | 82 нс |
| Флэтбафферы | 280 байтов | 830 нс | 290 нс |
| Протобуф | 120 байтов | 628 нс | 759 нс |
| Json | 301 байт | 740 нс | 500 нс |
Типичный рабочий процесс использования является следующим:
Образец проектов:
Необязательный:
sudo apt-get install -y binutils-dev uuid-dev flex bisonbrew install flex bisonchoco install winflexbison3pip3 install gilgit clone https://github.com/chronoxor/FastBinaryEncoding.git
cd FastBinaryEncoding
gil update cd build
./unix.sh cd build
./unix.sh cd build
unix.bat cd build
unix.bat cd build
mingw.bat cd build
vs.batЧтобы использовать быструю двоичную кодировку, вы должны предоставить доменную модель (он же бизнес -объекты). Доменная модель - это набор перечислений, флагов и структур, которые относятся друг к другу и могут быть агрегированы в некоторой иерархии.
Спецификация формата быстрого бинарного кодирования (FBE)
Существует примерная доменная модель, которая описывает отношение к счетам-балансовым уровням некоторой абстрактной торговой платформы:
// Package declaration
package proto
// Domain declaration
domain com.chronoxor
// Order side declaration
enum OrderSide : byte
{
buy;
sell;
}
// Order type declaration
enum OrderType : byte
{
market;
limit;
stop;
}
// Order declaration
struct Order
{
[key] int32 uid;
string symbol;
OrderSide side;
OrderType type;
double price = 0.0;
double volume = 0.0;
}
// Account balance declaration
struct Balance
{
[key] string currency;
double amount = 0.0;
}
// Account state declaration
flags State : byte
{
unknown = 0x00;
invalid = 0x01;
initialized = 0x02;
calculated = 0x04;
broken = 0x08;
good = initialized | calculated;
bad = unknown | invalid | broken;
}
// Account declaration
struct Account
{
[key] int32 uid;
string name;
State state = State.initialized | State.bad;
Balance wallet;
Balance? asset;
Order[] orders;
}Следующим шагом является компиляция доменной модели с использованием компилятора «FBEC», который создаст сгенерированный код для необходимого языка программирования.
Следующая команда создаст сгенерированный C ++ код:
fbec --c++ --input=proto.fbe --output=.Все возможные варианты компилятора «FBEC» следующие:
Usage: fbec [options]
Options:
--version show program ' s version number and exit
-h, --help show this help message and exit
-h HELP, --help=HELP Show help
-i INPUT, --input=INPUT
Input path
-o OUTPUT, --output=OUTPUT
Output path
-q, --quiet Launch in quiet mode. No progress will be shown!
-n INDENT, --indent=INDENT
Format indent. Default: 0
-t, --tabs Format with tabs. Default: off
--cpp Generate C++ code
--cpp-logging Generate C++ logging code
--csharp Generate C# code
--go Generate Go code
--java Generate Java code
--javascript Generate JavaScript code
--kotlin Generate Kotlin code
--python Generate Python code
--ruby Generate Ruby code
--swift Generate Swift code
--final Generate Final serialization code
--json Generate JSON serialization code
--proto Generate Sender/Receiver protocol codeСгенерированная доменная модель представлена с исходным кодом для конкретного языка. Просто добавьте его в свой проект и создайте его. Есть несколько вопросов и зависимостей, которые следует упомянуть:
<fmt/format.h> и <fmt/ostream.h> ;go get github.com/stretchr/testify );go get github.com/json-iterator/go );go get github.com/shopspring/decimal );go get github.com/google/uuid );gem install json
gem install uuidtoolsБыстрое двоичное кодирование (FBE) - это быстрый и компактный бинарный формат представления моделей отдельных доменов на разных языках и платформах программирования. Также FBE Format решает проблему версии протокола.
Следуйте приведенным ниже шагам, чтобы сериализовать любой объект домена:
Следуйте приведенным ниже шагам, чтобы десериализовать любой объект домена:
Вот эксперт сериализации FBE на языке C ++:
# include " ../proto/proto_models.h "
# include < iostream >
int main ( int argc, char ** argv)
{
// Create a new account with some orders
proto::Account account = { 1 , " Test " , proto::State::good, { " USD " , 1000.0 }, std::make_optional<proto::Balance>({ " EUR " , 100.0 }), {} };
account. orders . emplace_back ( 1 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::market, 1.23456 , 1000.0 );
account. orders . emplace_back ( 2 , " EURUSD " , proto::OrderSide::sell, proto::OrderType::limit, 1.0 , 100.0 );
account. orders . emplace_back ( 3 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::stop, 1.5 , 10.0 );
// Serialize the account to the FBE stream
FBE::proto::AccountModel<FBE::WriteBuffer> writer;
writer. serialize (account);
assert (writer. verify ());
// Show the serialized FBE size
std::cout << " FBE size: " << writer. buffer (). size () << std::endl;
// Deserialize the account from the FBE stream
FBE::proto::AccountModel<FBE::ReadBuffer> reader;
reader. attach (writer. buffer ());
assert (reader. verify ());
reader. deserialize (account);
// Show account content
std::cout << std::endl;
std::cout << account;
return 0 ;
}Вывод - следующее:
FBE size: 252
Account(
uid=1,
name="Test",
state=initialized|calculated|good,
wallet=Balance(currency="USD",amount=1000),
asset=Balance(currency="EUR",amount=100),
orders=[3][
Order(uid=1,symbol="EURUSD",side=buy,type=market,price=1.23456,volume=1000),
Order(uid=2,symbol="EURUSD",side=sell,type=limit,price=1,volume=100),
Order(uid=3,symbol="EURUSD",side=buy,type=stop,price=1.5,volume=10)
]
)
Можно достичь большей скорости сериализации, если ваш протокол достаточно зрелый, чтобы вы могли исправить его окончательную версию и отключить версию, которые требуют дополнительного размера и времени для обработки.
| Протокол | Размер сообщения | Время сериализации | Время деессериализации | Проверьте время |
|---|---|---|---|---|
| FBE | 252 байта | 88 нс | 98 нс | 33 нс |
| FBE финал | 152 байта | 57 нс | 81 нс | 28 нс |
Окончательная доменная модель может быть составлена с флагом -финал. В качестве результата дополнительные окончательные модели будут доступны для сериализации.
Следуйте приведенным ниже шагам, чтобы сериализовать любой объект домена в конечном формате:
Следуйте приведенным ниже шагам, чтобы десериализовать любой объект домена:
Вот измельчение окончательной сериализации FBE на языке C ++:
# include " ../proto/proto_models.h "
# include < iostream >
int main ( int argc, char ** argv)
{
// Create a new account with some orders
proto::Account account = { 1 , " Test " , proto::State::good, { " USD " , 1000.0 }, std::make_optional<proto::Balance>({ " EUR " , 100.0 }), {} };
account. orders . emplace_back ( 1 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::market, 1.23456 , 1000.0 );
account. orders . emplace_back ( 2 , " EURUSD " , proto::OrderSide::sell, proto::OrderType::limit, 1.0 , 100.0 );
account. orders . emplace_back ( 3 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::stop, 1.5 , 10.0 );
// Serialize the account to the FBE stream
FBE::proto::AccountFinalModel<FBE::WriteBuffer> writer;
writer. serialize (account);
assert (writer. verify ());
// Show the serialized FBE size
std::cout << " FBE final size: " << writer. buffer (). size () << std::endl;
// Deserialize the account from the FBE stream
FBE::proto::AccountFinalModel<FBE::ReadBuffer> reader;
reader. attach (writer. buffer ());
assert (reader. verify ());
reader. deserialize (account);
// Show account content
std::cout << std::endl;
std::cout << account;
return 0 ;
}Вывод - следующее:
FBE final size: 152
Account(
uid=1,
name="Test",
state=initialized|calculated|good,
wallet=Balance(currency="USD",amount=1000),
asset=Balance(currency="EUR",amount=100),
orders=[3][
Order(uid=1,symbol="EURUSD",side=buy,type=market,price=1.23456,volume=1000),
Order(uid=2,symbol="EURUSD",side=sell,type=limit,price=1,volume=100),
Order(uid=3,symbol="EURUSD",side=buy,type=stop,price=1.5,volume=10)
]
)
Если доменная модель, составленная с флагом -JSON, то код сериализации JSON будет генерироваться во всех объектах домена. В результате каждый объект домена может быть сериализован/десериализован в/из формата JSON.
Обратите внимание, что некоторые языки программирования имеют нативную поддержку JSON (JavaScript, Python). Другие языки требуют, чтобы сторонняя библиотека получила работу с JSON:
Вот эксперт сериализации JSON на языке C ++:
# include " ../proto/proto.h "
# include < iostream >
int main ( int argc, char ** argv)
{
// Create a new account with some orders
proto::Account account = { 1 , " Test " , proto::State::good, { " USD " , 1000.0 }, std::make_optional<proto::Balance>({ " EUR " , 100.0 }), {} };
account. orders . emplace_back ( 1 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::market, 1.23456 , 1000.0 );
account. orders . emplace_back ( 2 , " EURUSD " , proto::OrderSide::sell, proto::OrderType::limit, 1.0 , 100.0 );
account. orders . emplace_back ( 3 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::stop, 1.5 , 10.0 );
// Serialize the account to the JSON stream
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer (buffer);
FBE::JSON::to_json (writer, account);
// Show the serialized JSON and its size
std::cout << " JSON: " << buffer. GetString () << std::endl;
std::cout << " JSON size: " << buffer. GetSize () << std::endl;
// Parse the JSON document
rapidjson::Document json;
json. Parse (buffer. GetString ());
// Deserialize the account from the JSON stream
FBE::JSON::from_json (json, account);
// Show account content
std::cout << std::endl;
std::cout << account;
return 0 ;
}Вывод - следующее:
JSON: {
"uid":1,
"name":
"Test",
"state":6,
"wallet":{"currency":"USD","amount":1000.0},
"asset":{"currency":"EUR","amount":100.0},
"orders":[
{"uid":1,"symbol":"EURUSD","side":0,"type":0,"price":1.23456,"volume":1000.0},
{"uid":2,"symbol":"EURUSD","side":1,"type":1,"price":1.0,"volume":100.0},
{"uid":3,"symbol":"EURUSD","side":0,"type":2,"price":1.5,"volume":10.0}
]
}
JSON size: 353
Account(
uid=1,
name="Test",
state=initialized|calculated|good,
wallet=Balance(currency="USD",amount=1000),
asset=Balance(currency="EUR",amount=100),
orders=[3][
Order(uid=1,symbol="EURUSD",side=buy,type=market,price=1.23456,volume=1000),
Order(uid=2,symbol="EURUSD",side=sell,type=limit,price=1,volume=100),
Order(uid=3,symbol="EURUSD",side=buy,type=stop,price=1.5,volume=10)
]
)
Пакеты объявляются с помощью имени пакета и смещения структуры (необязательно). Offset будет добавлено к увеличению типа структуры, если не было предоставлено явным.
Вот пример простого объявления пакета:
// Package declaration. Offset is 0.
package proto
// Struct type number is 1 (proto offset 0 + 1)
struct Struct1
{
...
}
// Struct type number is 2 (proto offset 0 + 2)
struct Struct2
{
...
}Один пакет может быть импортирован в другой, и все перечисления, флаги и структуры могут быть использованы в текущем пакете. Здесь используется смещение пакета, чтобы избежать пересечения типов структур:
// Package declaration. Offset is 10.
package protoex offset 10
// Package import
import proto
// Struct type number is 11 (protoex offset 10 + 1)
struct Struct11
{
// Struct1 is reused form the imported package
proto.Struct1 s1;
...
}
// Struct type number is 12 (protoex offset 10 + 2)
struct Struct12
{
...
}Также возможен импорт нескольких пакетов:
// Package declaration. Offset is 100.
package test offset 100
// Package import
import proto
import protoex
...Импорт пакета реализуется с использованием:
Некоторые из поданных структур (один или много) могут быть отмечены атрибутом «key]». В качестве результата, соответствующего соответствующим операторам, будет сгенерировано, что позволяет сравнивать два экземпляра структуры (равенство, упорядочение, хэширование) с отмеченными полями. Эта способность позволяет использовать структуру в качестве ключа в ассоциативной карте и хэш -контейнерах.
Пример ниже демонстрирует использование атрибута [Key] ':
struct MyKeyStruct
{
[key] int32 uid;
[key] stirng login;
string name;
string address;
}После генерации кода для языка C ++ будет создан следующий сопоставимый класс:
struct MyKeyStruct
{
int32_t uid;
::sample::stirng login;
std::string name;
std::string address;
...
bool operator ==( const MyKeyStruct& other) const noexcept
{
return (
(uid == other. uid )
&& (login == other. login )
);
}
bool operator !=( const MyKeyStruct& other) const noexcept { return ! operator ==(other); }
bool operator <( const MyKeyStruct& other) const noexcept
{
if (uid < other. uid )
return true ;
if (other. uid < uid)
return false ;
if (login < other. login )
return true ;
if (other. login < login)
return false ;
return false ;
}
bool operator <=( const MyKeyStruct& other) const noexcept { return operator <(other) || operator ==(other); }
bool operator >( const MyKeyStruct& other) const noexcept { return ! operator <=(other); }
bool operator >=( const MyKeyStruct& other) const noexcept { return ! operator <(other); }
...
};Числа типов структуры автоматически увеличиваются, пока вы не предоставите его вручную. Есть две возможности:
Пример ниже демонстрирует идею:
// Package declaration. Offset is 0.
package proto
// Struct type number is 1 (implicit declared)
struct Struct1
{
...
}
// Struct type number is 2 (implicit declared)
struct Struct2
{
...
}
// Struct type number is 10 (explicit declared, shifted to 10)
struct Struct10(+10)
{
...
}
// Struct type number is 11 (implicit declared)
struct Struct11
{
...
}
// Struct type number is 100 (explicit declared, forced to 100)
struct Struct100(100)
{
...
}
// Struct type number is 12 (implicit declared)
struct Struct12
{
...
}Контроки могут быть унаследованы от другой структуры. В этом случае все поля из базовой структуры будут присутствовать в детском.
package proto
// Struct type number is 1
struct StructBase
{
bool f1;
int8 f2;
}
// Struct type number is 2
struct StructChild : StructBase
{
// bool f1 - will be inherited from StructBase
// int8 f2 - will be inherited from StructBase
int16 f3;
int32 f4;
}Также можно повторно использовать базовый номер типа структуры у ребенка, используя оператор '= base'. Это полезно, когда вы расширяете структуру из стороннего импортного пакета:
// Package declaration. Offset is 10.
package protoex offset 10
// Package import
import proto
// Struct type number is 1
struct StructChild(base) : proto.StructBase
{
// bool f1 - will be inherited from proto.StructBase
// int8 f2 - will be inherited from proto.StructBase
int16 f3;
int32 f4;
}Управление версиями прост с быстрой бинарной кодировкой.
Предположим, у вас есть оригинальный протокол:
package proto
enum MyEnum
{
value1;
value2;
}
flags MyFlags
{
none = 0x00;
flag1 = 0x01;
flag2 = 0x02;
flag3 = 0x04;
}
struct MyStruct
{
bool field1;
byte field2;
char field3;
}Вам нужно расширить его с новыми значениями Enum, Flag и Struct. Просто добавьте требуемые значения в конце соответствующих объявлений:
package proto
enum MyEnum
{
value1;
value2;
value3; // New value
value4; // New value
}
flags MyFlags
{
none = 0x00;
flag1 = 0x01;
flag2 = 0x02;
flag3 = 0x04;
flag4 = 0x08; // New value
flag5 = 0x10; // New value
}
struct MyStruct
{
bool field1;
byte field2;
char field3;
int32 field4; // New field (default value is 0)
int64 field5 = 123456; // New field (default value is 123456)
}Теперь вы можете сериализовать и десериализовать структуры в разных комбинациях:
Если вы не можете изменить какой-то сторонний протокол, вы все равно можете иметь решение о его расширении. Просто создайте новый протокол и импортируйте сторонний. Затем расширяйте структуры с наследством:
package protoex
import proto
struct MyStructEx(base) : proto.MyStruct
{
int32 field4; // New field (default value is 0)
int64 field5 = 123456; // New field (default value is 123456)
}Если доменная модель, составленная с флагом -то, что будет сгенерирован код протокола отправителя/приемника.
Интерфейс отправителя содержит методы «Send (struct)» для всех доменных структур. Кроме того, он имеет абстрактный метод «Onsend (Data, Size)», который должен быть реализован для отправки сериализованных данных в сокет, трубу и т. Д.
Интерфейс приемника содержит обработчики OnerCeive (struct) для всех доменных структур. Кроме того, он имеет общедоступный метод «OneCeive (тип, данные, размер), который следует использовать для подачи приемника полученными данными из розетки, трубы и т. Д.
Вот эксперт использования протокола связи отправителя/приемника на языке C ++:
# include " ../proto/proto_protocol.h "
# include < iostream >
class MySender : public FBE ::proto::Sender<FBE::WriteBuffer>
{
protected:
size_t onSend ( const void * data, size_t size) override
{
// Send nothing...
return 0 ;
}
void onSendLog ( const std::string& message) const override
{
std::cout << " onSend: " << message << std::endl;
}
};
class MyReceiver : public FBE ::proto::Receiver<FBE::WriteBuffer>
{
protected:
void onReceive ( const proto::Order& value) override {}
void onReceive ( const proto::Balance& value) override {}
void onReceive ( const proto::Account& value) override {}
void onReceiveLog ( const std::string& message) const override
{
std::cout << " onReceive: " << message << std::endl;
}
};
int main ( int argc, char ** argv)
{
MySender sender;
// Enable logging
sender. logging ( true );
// Create and send a new order
proto::Order order = { 1 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::market, 1.23456 , 1000.0 };
sender. send (order);
// Create and send a new balance wallet
proto::Balance balance = { " USD " , 1000.0 };
sender. send (balance);
// Create and send a new account with some orders
proto::Account account = { 1 , " Test " , proto::State::good, { " USD " , 1000.0 }, std::make_optional<proto::Balance>({ " EUR " , 100.0 }), {} };
account. orders . emplace_back ( 1 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::market, 1.23456 , 1000.0 );
account. orders . emplace_back ( 2 , " EURUSD " , proto::OrderSide::sell, proto::OrderType::limit, 1.0 , 100.0 );
account. orders . emplace_back ( 3 , " EURUSD " , proto::OrderSide::buy, proto::OrderType::stop, 1.5 , 10.0 );
sender. send (account);
MyReceiver receiver;
// Enable logging
receiver. logging ( true );
// Receive all data from the sender
receiver. receive (sender. buffer (). data (), sender. buffer (). size ());
return 0 ;
}Вывод - следующее:
onSend: Order(uid=1,symbol="EURUSD",side=buy,type=market,price=1.23456,volume=1000)
onSend: Balance(currency="USD",amount=1000)
onSend: Account(uid=1,name="Test",state=initialized|calculated|good,wallet=Balance(currency="USD",amount=1000),asset=Balance(currency="EUR",amount=100),orders=[3][Order(uid=1,symbol="EURUSD",side=buy,type=market,price=1.23456,volume=1000),Order(uid=2,symbol="EURUSD",side=sell,type=limit,price=1,volume=100),Order(uid=3,symbol="EURUSD",side=buy,type=stop,price=1.5,volume=10)])
onReceive: Order(uid=1,symbol="EURUSD",side=buy,type=market,price=1.23456,volume=1000)
onReceive: Balance(currency="USD",amount=1000)
onReceive: Account(uid=1,name="Test",state=initialized|calculated|good,wallet=Balance(currency="USD",amount=1000),asset=Balance(currency="EUR",amount=100),orders=[3][Order(uid=1,symbol="EURUSD",side=buy,type=market,price=1.23456,volume=1000),Order(uid=2,symbol="EURUSD",side=sell,type=limit,price=1,volume=100),Order(uid=3,symbol="EURUSD",side=buy,type=stop,price=1.5,volume=10)])
Все тесты используют одну и ту же модель домена для создания одной учетной записи с тремя заказами:
Account account = { 1 , " Test " , State::good, { " USD " , 1000.0 }, std::make_optional<Balance>({ " EUR " , 100.0 }), {} };
account.orders.emplace_back( 1 , " EURUSD " , OrderSide::buy, OrderType::market, 1.23456 , 1000.0 );
account.orders.emplace_back( 2 , " EURUSD " , OrderSide::sell, OrderType::limit, 1.0 , 100.0 );
account.orders.emplace_back( 3 , " EURUSD " , OrderSide::buy, OrderType::stop, 1.5 , 10.0 );Код сериализации C ++:
BENCHMARK_FIXTURE (SerializationFixture, " Serialize " )
{
// Reset FBE stream
writer. reset ();
// Serialize the account to the FBE stream
writer. serialize (account);
}Результаты эталона сериализации:
| Язык и платформа | Размер сообщения | Скорость сериализации | Время сериализации |
|---|---|---|---|
| C ++ Win64 | 252 байта | 10 416 667 Ops/s | 96 нс |
| C ++ win64 (финал) | 152 байта | 16 129 032 Ops/s | 62 нс |
| C ++ win64 (json) | 353 байта | 926 784 Опс/с | 1 079 нс |
| C# Win64 | 252 байта | 1 432 665 Ops/s | 698 нс |
| C# win64 (финал) | 152 байта | 1 597 444 Ops/s | 626 нс |
| C# win64 (json) | 341 байт | 434 783 Опс/с | 2 300 нс |
| Go Win64 | 252 байта | 2 739 726 OPS/S | 365 нс |
| Go Win64 (финал) | 152 байта | 2 949 852 Ops/S | 339 нс |
| Go Win64 (JSON) | 341 байт | 258 732 Опс/с | 3 865 нс |
| Java Win64 | 252 байта | 4 247 162 Ops/S | 236 нс |
| Java Win64 (финал) | 152 байта | 4 883 205 Ops/s | 205 нс |
| Java Win64 (JSON) | 353 байта | 213 983 Опс/с | 4 673 нс |
| JavaScript win64 | 252 байта | 93 416 Опс/с | 10 705 нс |
| JavaScript win64 (финал) | 152 байта | 112 665 Опс/с | 8 876 нс |
| JavaScript win64 (JSON) | 341 байт | 217 637 Опс/с | 4 595 нс |
| Kotlin Win64 | 252 байта | 3 546 694 OPS/S | 282 нс |
| Kotlin Win64 (финал) | 152 байта | 4 096 406 OPS/S | 244 нс |
| Kotlin Win64 (JSON) | 353 байта | 185 788 Опс/с | 5 382 нс |
| Python Win64 | 252 байта | 9 434 Опс/с | 105 999 нс |
| Python Win64 (финал) | 152 байта | 11 635 Опс/с | 85 945 нс |
| Python Win64 (JSON) | 324 байта | 61 737 Опс/с | 16 198 нс |
| Ruby Win64 | 252 байта | 23 013 Опс/с | 43 453 нс |
| Ruby Win64 (финал) | 152 байта | 33 361 Опс/с | 29 975 нс |
| Ruby Win64 (JSON) | 353 байта | 50 842 OPS/с | 19 669 нс |
| Swift MacOS | 252 байта | 74 002 Ops/s | 13 513 нс |
| Swift macOS (финал) | 152 байта | 100 755 Ops/s | 9 925 нс |
| Swift MacOS (JSON) | 353 байта | 18 534 Опс/с | 53 953 нс |
Код C ++ Deserialization Code:
BENCHMARK_FIXTURE (DeserializationFixture, " Deserialize " )
{
// Deserialize the account from the FBE stream
reader. deserialize (deserialized);
}Результаты эталона десериализации:
| Язык и платформа | Размер сообщения | Уровень десериализации | Время деессериализации |
|---|---|---|---|
| C ++ Win64 | 252 байта | 9 523 810 Ops/s | 105 нс |
| C ++ win64 (финал) | 152 байта | 10 989 011 Ops/s | 91 нс |
| C ++ win64 (json) | 353 байта | 1 375 516 OPS/S | 727 нс |
| C# Win64 | 252 байта | 1 014 199 Ops/S | 986 нс |
| C# win64 (финал) | 152 байта | 1 607 717 Ops/s | 622 нс |
| C# win64 (json) | 341 байт | 258 532 Опс/с | 3 868 нс |
| Go Win64 | 252 байта | 1 510 574 OPS/S | 662 нс |
| Go Win64 (финал) | 152 байта | 1 540 832 Ops/s | 649 нс |
| Go Win64 (JSON) | 341 байт | 251 825 Опс/с | 3 971 нс |
| Java Win64 | 252 байта | 2 688 084 OPS/S | 372 нс |
| Java Win64 (финал) | 152 байта | 3 036 020 Ops/S | 329 нс |
| Java Win64 (JSON) | 353 байта | 308 675 Опс/с | 3 240 нс |
| JavaScript win64 | 252 байта | 133 892 Опс/с | 7 469 нс |
| JavaScript win64 (финал) | 152 байта | 292 273 Опс/с | 3 422 нс |
| JavaScript win64 (JSON) | 341 байт | 289 417 Опс/с | 3 455 нс |
| Kotlin Win64 | 252 байта | 2 280 923 Ops/S | 438 нс |
| Kotlin Win64 (финал) | 152 байта | 2 652 728 Ops/S | 277 нс |
| Kotlin Win64 (JSON) | 353 байта | 250 524 Опс/с | 3 992 нс |
| Python Win64 | 252 байта | 8 305 Опс/с | 120 411 нс |
| Python Win64 (финал) | 152 байта | 11 661 Опс/с | 85 758 нс |
| Python Win64 (JSON) | 324 байта | 48 859 Опс/с | 20 467 нс |
| Ruby Win64 | 252 байта | 24 351 Опс/с | 41 066 нс |
| Ruby Win64 (финал) | 152 байта | 33 555 Опс/с | 29 802 нс |
| Ruby Win64 (JSON) | 353 байта | 42 860 OPS/с | 23 331 нс |
| Swift MacOS | 252 байта | 86 288 Опс/с | 11 589 нс |
| Swift macOS (финал) | 152 байта | 10 3519 Опс/с | 9 660 нс |
| Swift MacOS (JSON) | 353 байта | 17 077 Опс/с | 58 558 нс |
Проверьте контрольный код C ++:
BENCHMARK_FIXTURE (VerifyFixture, " Verify " )
{
// Verify the account
model. verify ();
}Проверьте результаты эталона:
| Язык и платформа | Размер сообщения | Проверьте скорость | Проверьте время |
|---|---|---|---|
| C ++ Win64 | 252 байта | 31 250 000 Ops/S | 32 нс |
| C ++ win64 (финал) | 152 байта | 35 714 286 OPS/S | 28 нс |
| C# Win64 | 252 байта | 4 504 505 OPS/S | 222 нс |
| C# win64 (финал) | 152 байта | 8 064 516 Ops/S | 124 нс |
| Go Win64 | 252 байта | 8 474 576 Ops/s | 118 нс |
| Go Win64 (финал) | 152 байта | 9 090 909 OPS/S | 110 нс |
| Java Win64 | 252 байта | 11 790 374 Ops/s | 85 нс |
| Java Win64 (финал) | 152 байта | 16 205 533 Ops/s | 62 нс |
| JavaScript win64 | 252 байта | 1 105 627 Ops/s | 905 нс |
| JavaScript win64 (финал) | 152 байта | 5 700 408 Ops/S | 175 нс |
| Kotlin Win64 | 252 байта | 8 625 935 Ops/s | 116 нс |
| Kotlin Win64 (финал) | 152 байта | 13 373 757 Ops/s | 75 нс |
| Python Win64 | 252 байта | 20 825 Опс/с | 48 019 нс |
| Python Win64 (финал) | 152 байта | 23 590 Опс/с | 42 391 нс |
| Ruby Win64 | 252 байта | 57 201 Ops/s | 17 482 нс |
| Ruby Win64 (финал) | 152 байта | 74 262 Опс/с | 13 466 нс |
| Swift MacOS | 252 байта | 164 446 Опс/с | 6 081 нс |
| Swift macOS (финал) | 152 байта | 228 154 Опс/с | 4 383 нс |