A codificação binária rápida permite descrever modelos de domínio, objetos de negócios, estruturas de dados complexas, solicitações e respostas do cliente/servidor e gerar código nativo para diferentes linguagens e plataformas de programação.
Documentação de codificação binária rápida
Downloads de codificação binária rápida
Especificação de codificação binária rápida
A comparação de desempenho com outros protocolos pode ser encontrada aqui:
| Protocolo | Tamanho da mensagem | Tempo de serialização | Tempo de desserialização |
|---|---|---|---|
| Cap'n'proto | 208 bytes | 558 ns | 359 ns |
| Fastbinária | 234 bytes | 66 ns | 82 ns |
| Planície | 280 bytes | 830 ns | 290 ns |
| Protobuf | 120 bytes | 628 ns | 759 ns |
| JSON | 301 bytes | 740 ns | 500 ns |
O fluxo de trabalho de uso típico é o seguinte:
Projetos de amostra:
Opcional:
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.batPara usar a codificação binária rápida, você deve fornecer um modelo de domínio (também conhecido como objetos de negócios). Um modelo de domínio é um conjunto de enumes, bandeiras e estruturas que se relacionam e podem ser agregadas em alguma hierarquia.
Especificação de formato de codificação binária rápida (FBE)
Existe um modelo de domínio de amostra que descreve a relação de ordens de contas de alguma plataforma de negociação abstrata:
// 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;
}A próxima etapa é uma compilação de modelo de domínio usando o compilador 'FBEC' que criará um código gerado para a linguagem de programação necessária.
O comando a seguir criará um código gerado por C ++:
fbec --c++ --input=proto.fbe --output=.Todas as opções possíveis para o compilador 'FBEC' são as seguintes:
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 codeO modelo de domínio gerado é representado com o código -fonte para o idioma específico. Basta adicioná -lo ao seu projeto e construí -lo. Existem várias questões e dependências que devem ser mencionadas:
<fmt/format.h> e <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 uuidtoolsA codificação binária rápida (FBE) é um formato binário rápido e compacto de representar modelos de domínio único em diferentes linguagens e plataformas de programação. O formato FBE também resolve o problema de versão do protocolo.
Siga as etapas abaixo para seriarizar qualquer objeto de domínio:
Siga as etapas abaixo para desserializar qualquer objeto de domínio:
Aqui está um exato da serialização do FBE na linguagem 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 ;
}A saída é a seguinte:
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)
]
)
É possível obter mais velocidade de serialização se o seu protocolo estiver maduro o suficiente para que você possa corrigir sua versão final e desativar o versão que requer tamanho e tempo extras para processar.
| Protocolo | Tamanho da mensagem | Tempo de serialização | Tempo de desserialização | Verifique o tempo |
|---|---|---|---|---|
| Fbe | 252 bytes | 88 ns | 98 ns | 33 ns |
| FBE final | 152 bytes | 57 ns | 81 ns | 28 ns |
O modelo de domínio final pode ser compilado com -Final Final. Como resultado, modelos finais adicionais estarão disponíveis para serialização.
Siga as etapas abaixo para seriarizar qualquer objeto de domínio no formato final:
Siga as etapas abaixo para desserializar qualquer objeto de domínio:
Aqui está um exato da serialização final do FBE na linguagem 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 ;
}A saída é a seguinte:
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)
]
)
Se o modelo de domínio compilado com o sinalizador --json, o código de serialização JSON será gerado em todos os objetos de domínio. Como resultado, cada objeto de domínio pode ser serializado/desserializado no formato JSON.
Observe que algumas linguagens de programação têm suporte nativo ao JSON (JavaScript, Python). Outros idiomas exigem que a biblioteca de terceiros faça trabalho com o JSON:
Aqui está um exmple da serialização JSON na linguagem 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 ;
}A saída é a seguinte:
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)
]
)
Os pacotes são declarados com o nome do pacote e o deslocamento das estruturas (opcional). O deslocamento será adicionado ao tipo de estrutura incrementado se não for fornecido explícito.
Aqui está um exemplo da declaração simples de pacote:
// 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
{
...
}Um pacote pode ser importado para outro e todas as enumistas, sinalizadores e estruturas podem ser reutilizadas no pacote atual. O deslocamento do pacote é usado aqui para evitar que os tipos de estruturas interseção:
// 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
{
...
}A importação de pacotes múltiplos também é possível:
// Package declaration. Offset is 100.
package test offset 100
// Package import
import proto
import protoex
...A importação de pacotes é implementada usando:
Alguns dos arquivos da estrutura (um ou muitos) podem ser marcados com o atributo '[key]'. Como o resultado correspondente, os operadores de comparação serão gerados, que permitem comparar duas instâncias da estrutura (igualdade, ordenação, hash) por campos marcados. Essa habilidade permite usar a estrutura como uma chave nos contêineres de mapa associativo e hash.
Exemplo abaixo demonstra o uso do atributo '[key]':
struct MyKeyStruct
{
[key] int32 uid;
[key] stirng login;
string name;
string address;
}Após a geração de código para a linguagem C ++, a seguinte classe comparável será gerada:
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); }
...
};Os números de tipo de estrutura são aumentados automaticamente até que você o forneça manualmente. Existem duas possibilidades:
Exemplo abaixo demonstra a ideia:
// 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
{
...
}As estruturas podem ser herdadas de outra estrutura. Nesse caso, todos os campos da estrutura da base estarão presentes em uma criança.
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;
}Também é possível reutilizar o número do tipo de estrutura base em uma criança usando o operador '= base'. É útil quando você estende a estrutura do pacote importado de terceiros:
// 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;
}A versão é simples com a codificação binária rápida.
Suponha que você tenha um protocolo original:
package proto
enum MyEnum
{
value1;
value2;
}
flags MyFlags
{
none = 0x00;
flag1 = 0x01;
flag2 = 0x02;
flag3 = 0x04;
}
struct MyStruct
{
bool field1;
byte field2;
char field3;
}Você precisa estendê -lo com novos valores de enum, sinalizador e estrutura. Basta adicionar valores necessários ao final das declarações correspondentes:
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)
}Agora você pode serializar e desserializar estruturas em diferentes combinações:
Se você não conseguir modificar algum protocolo de terceiros, ainda poderá estendê-lo. Basta criar um novo protocolo e importar terceiros para ele. Em seguida, estenda estruturas com herança:
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)
}Se o modelo de domínio compilado com - -sender sinalizador, o código do protocolo de remetente/receptor será gerado.
A interface do remetente contém métodos 'send (struct)' para todas as estruturas do modelo de domínio. Também possui o método abstrato de 'Onsend (dados, tamanho), que deve ser implementado para enviar dados serializados para um soquete, tubo, etc.
A interface do receptor contém manipuladores 'OnReceive (STRUT) para todas as estruturas de modelo de domínio. Também possui método público 'OnReceive (tipo, dados, tamanho), que deve ser usado para alimentar o receptor com dados recebidos de um soquete, tubo, etc.
Aqui está um exmitado de usar o protocolo de comunicação do remetente/receptor na linguagem 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 ;
}A saída é a seguinte:
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)])
Todos os benchmarks usam o mesmo modelo de domínio para criar uma única conta com três pedidos:
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ódigo C ++ de referência de serialização:
BENCHMARK_FIXTURE (SerializationFixture, " Serialize " )
{
// Reset FBE stream
writer. reset ();
// Serialize the account to the FBE stream
writer. serialize (account);
}Resultados de referência de serialização:
| Idioma e plataforma | Tamanho da mensagem | Taxa de serialização | Tempo de serialização |
|---|---|---|---|
| C ++ Win64 | 252 bytes | 10 416 667 OPS/S | 96 ns |
| C ++ Win64 (final) | 152 bytes | 16 129 032 OPS/S | 62 ns |
| C ++ Win64 (JSON) | 353 bytes | 926 784 OPS/S. | 1 079 ns |
| C# Win64 | 252 bytes | 1 432 665 OPS/S | 698 ns |
| C# Win64 (final) | 152 bytes | 1 597 444 OPS/S | 626 ns |
| C# Win64 (JSON) | 341 bytes | 434 783 OPS/S. | 2 300 ns |
| Vá Win64 | 252 bytes | 2 739 726 OPS/S | 365 ns |
| Vá Win64 (final) | 152 bytes | 2 949 852 OPS/S | 339 ns |
| Vá Win64 (JSON) | 341 bytes | 258 732 OPS/S. | 3 865 ns |
| Java Win64 | 252 bytes | 4 247 162 OPS/S | 236 ns |
| Java Win64 (final) | 152 bytes | 4 883 205 OPS/S | 205 ns |
| Java Win64 (JSON) | 353 bytes | 213 983 OPS/S. | 4 673 ns |
| JavaScript Win64 | 252 bytes | 93 416 OPS/S. | 10 705 ns |
| JavaScript Win64 (final) | 152 bytes | 112 665 OPS/S. | 8 876 ns |
| JavaScript Win64 (JSON) | 341 bytes | 217 637 OPS/S. | 4 595 ns |
| Kotlin Win64 | 252 bytes | 3 546 694 OPS/S | 282 ns |
| Kotlin Win64 (final) | 152 bytes | 4 096 406 OPS/S | 244 ns |
| Kotlin Win64 (JSON) | 353 bytes | 185 788 OPS/S. | 5 382 ns |
| Python Win64 | 252 bytes | 9 434 OPS/S. | 105 999 ns |
| Python Win64 (final) | 152 bytes | 11 635 OPS/S. | 85 945 ns |
| Python Win64 (JSON) | 324 bytes | 61 737 OPS/S. | 16 198 ns |
| Ruby Win64 | 252 bytes | 23 013 OPS/S. | 43 453 ns |
| Ruby Win64 (final) | 152 bytes | 33 361 OPS/S. | 29 975 ns |
| Ruby Win64 (JSON) | 353 bytes | 50 842 OPS/S. | 19 669 ns |
| MacOS Swift | 252 bytes | 74 002 OPS/S. | 13 513 ns |
| MacOS Swift (final) | 152 bytes | 100 755 OPS/S. | 9 925 ns |
| MacOS Swift (JSON) | 353 bytes | 18 534 OPS/S. | 53 953 ns |
Código C ++ de benchmark de deserialização:
BENCHMARK_FIXTURE (DeserializationFixture, " Deserialize " )
{
// Deserialize the account from the FBE stream
reader. deserialize (deserialized);
}Resultados de benchmark de desserialização:
| Idioma e plataforma | Tamanho da mensagem | Taxa de desserialização | Tempo de desserialização |
|---|---|---|---|
| C ++ Win64 | 252 bytes | 9 523 810 OPS/S | 105 ns |
| C ++ Win64 (final) | 152 bytes | 10 989 011 OPS/S | 91 ns |
| C ++ Win64 (JSON) | 353 bytes | 1 375 516 OPS/S | 727 ns |
| C# Win64 | 252 bytes | 1 014 199 OPS/S | 986 ns |
| C# Win64 (final) | 152 bytes | 1 607 717 OPS/S | 622 ns |
| C# Win64 (JSON) | 341 bytes | 258 532 OPS/S. | 3 868 ns |
| Vá Win64 | 252 bytes | 1 510 574 OPS/S | 662 ns |
| Vá Win64 (final) | 152 bytes | 1 540 832 OPS/S | 649 ns |
| Vá Win64 (JSON) | 341 bytes | 251 825 OPS/S. | 3 971 ns |
| Java Win64 | 252 bytes | 2 688 084 OPS/S | 372 ns |
| Java Win64 (final) | 152 bytes | 3 036 020 OPS/S | 329 ns |
| Java Win64 (JSON) | 353 bytes | 308 675 OPS/S. | 3 240 ns |
| JavaScript Win64 | 252 bytes | 133 892 OPS/S. | 7 469 ns |
| JavaScript Win64 (final) | 152 bytes | 292 273 OPS/S. | 3 422 ns |
| JavaScript Win64 (JSON) | 341 bytes | 289 417 OPS/S. | 3 455 ns |
| Kotlin Win64 | 252 bytes | 2 280 923 OPS/S | 438 ns |
| Kotlin Win64 (final) | 152 bytes | 2 652 728 OPS/S | 277 ns |
| Kotlin Win64 (JSON) | 353 bytes | 250 524 OPS/S. | 3 992 ns |
| Python Win64 | 252 bytes | 8 305 OPS/S. | 120 411 ns |
| Python Win64 (final) | 152 bytes | 11 661 OPS/S. | 85 758 ns |
| Python Win64 (JSON) | 324 bytes | 48 859 OPS/S. | 20 467 ns |
| Ruby Win64 | 252 bytes | 24 351 OPS/S. | 41 066 ns |
| Ruby Win64 (final) | 152 bytes | 33 555 OPS/S. | 29 802 ns |
| Ruby Win64 (JSON) | 353 bytes | 42 860 OPS/S. | 23 331 ns |
| MacOS Swift | 252 bytes | 86 288 OPS/S. | 11 589 ns |
| MacOS Swift (final) | 152 bytes | 10 3519 OPS/S. | 9 660 ns |
| MacOS Swift (JSON) | 353 bytes | 17 077 OPS/S. | 58 558 ns |
Verifique o código C ++ Benchmark:
BENCHMARK_FIXTURE (VerifyFixture, " Verify " )
{
// Verify the account
model. verify ();
}Verifique os resultados de referência:
| Idioma e plataforma | Tamanho da mensagem | Verifique a taxa | Verifique o tempo |
|---|---|---|---|
| C ++ Win64 | 252 bytes | 31 250 000 OPS/S | 32 ns |
| C ++ Win64 (final) | 152 bytes | 35 714 286 OPS/S | 28 ns |
| C# Win64 | 252 bytes | 4 504 505 OPS/S | 222 ns |
| C# Win64 (final) | 152 bytes | 8 064 516 OPS/S | 124 ns |
| Vá Win64 | 252 bytes | 8 474 576 OPS/S | 118 ns |
| Vá Win64 (final) | 152 bytes | 9 090 909 OPS/S | 110 ns |
| Java Win64 | 252 bytes | 11 790 374 OPS/S | 85 ns |
| Java Win64 (final) | 152 bytes | 16 205 533 OPS/S | 62 ns |
| JavaScript Win64 | 252 bytes | 1 105 627 OPS/S | 905 ns |
| JavaScript Win64 (final) | 152 bytes | 5 700 408 OPS/S | 175 ns |
| Kotlin Win64 | 252 bytes | 8 625 935 OPS/S | 116 ns |
| Kotlin Win64 (final) | 152 bytes | 13 373 757 OPS/S | 75 ns |
| Python Win64 | 252 bytes | 20 825 OPS/S. | 48 019 ns |
| Python Win64 (final) | 152 bytes | 23 590 OPS/S. | 42 391 ns |
| Ruby Win64 | 252 bytes | 57 201 OPS/S. | 17 482 ns |
| Ruby Win64 (final) | 152 bytes | 74 262 OPS/S. | 13 466 ns |
| MacOS Swift | 252 bytes | 164 446 OPS/S. | 6 081 ns |
| MacOS Swift (final) | 152 bytes | 228 154 OPS/S. | 4 383 ns |