Le codage binaire rapide permet de décrire tous les modèles de domaine, les objets métier, les structures de données complexes, les demandes et réponses client / serveur et de générer du code natif pour différents langages et plateformes de programmation.
Documentation en codage binaire rapide
Téléchargements de codage binaire rapide
Spécification de codage binaire rapide
La comparaison des performances avec d'autres protocoles peut être trouvée ici:
| Protocole | Taille du message | Temps de sérialisation | Temps de désérialisation |
|---|---|---|---|
| Cap'n'proto | 208 octets | 558 ns | 359 ns |
| Fastbinaryencoding | 234 octets | 66 ns | 82 ns |
| Pelures à plat | 280 octets | 830 ns | 290 ns |
| Protobuf | 120 octets | 628 ns | 759 ns |
| Json | 301 octets | 740 ns | 500 ns |
Le flux de travail d'utilisation typique est le suivant:
Exemples de projets:
Facultatif:
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.batPour utiliser un encodage binaire rapide, vous devez fournir un modèle de domaine (AKA Business Objectts). Un modèle de domaine est un ensemble d'énumériques, de drapeaux et de structures qui se rapportent les uns aux autres et pourraient être agrégés dans une certaine hiérarchie.
Spécification du format de codage binaire rapide (FBE)
Il existe un exemple de modèle de domaine qui décrit la relation de comptes-bilan-Orders d'une plateforme de trading abstraite:
// 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;
}L'étape suivante est une compilation de modèle de domaine utilisant le compilateur «FBEC» qui créera un code généré pour le langage de programmation requis.
La commande suivante créera un code généré C ++:
fbec --c++ --input=proto.fbe --output=.Toutes les options possibles pour le compilateur «FBEC» sont les suivantes:
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 codeLe modèle de domaine généré est représenté avec du code source pour la langue particulière. Ajoutez-le simplement à votre projet et construisez-le. Il y a plusieurs problèmes et dépendances qui doivent être mentionnés:
<fmt/format.h> et <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 uuidtoolsLe codage binaire rapide (FBE) est un format binaire rapide et compact de représentation de modèles de domaine unique dans différents langages de programmation et plates-formes. Le format FBE résout également le problème du versement du protocole.
Suivez les étapes ci-dessous afin de sérialiser n'importe quel objet de domaine:
Suivez les étapes ci-dessous afin de désérialiser tout objet de domaine:
Voici un exemple de sérialisation FBE dans la langue 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 ;
}La sortie est la suivante:
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)
]
)
Il est possible d'atteindre plus de vitesse de sérialisation si votre protocole est suffisamment mature afin que vous puissiez corriger sa version finale et désactiver le versioning qui nécessite une taille supplémentaire et du temps pour traiter.
| Protocole | Taille du message | Temps de sérialisation | Temps de désérialisation | Vérifiez le temps |
|---|---|---|---|---|
| Fbe | 252 octets | 88 ns | 98 ns | 33 ns |
| FBE FINAL | 152 octets | 57 ns | 81 ns | 28 ns |
Le modèle de domaine final peut être compilé avec un drapeau final. En conséquence, des modèles finaux supplémentaires seront disponibles pour la sérialisation.
Suivez les étapes ci-dessous afin de sérialiser n'importe quel objet de domaine au format final:
Suivez les étapes ci-dessous afin de désérialiser tout objet de domaine:
Voici un exmple de la sérialisation finale FBE dans le langage 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 ;
}La sortie est la suivante:
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)
]
)
Si le modèle de domaine compilé avec l'indicateur --json, le code de sérialisation JSON sera généré dans tous les objets de domaine. En conséquence, chaque objet de domaine peut être sérialisé / désérialisé au format JSON.
Veuillez noter que certains langages de programmation ont un support JSON natif (JavaScript, Python). D'autres langues nécessitent une bibliothèque tierce pour travailler avec JSON:
Voici un exemple de la sérialisation JSON en langue 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 ;
}La sortie est la suivante:
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)
]
)
Les packages sont déclarés avec le nom du package et le décalage des structures (facultatif). Le décalage sera ajouté au type de structure incrémenté si n'est pas fourni explicite.
Voici un exemple de la déclaration de package simple:
// 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
{
...
}Un package peut être importé dans un autre et tous les énumérations, drapeaux et structures peuvent être réutilisés dans le package actuel. Le décalage du package est utilisé ici pour éviter l'intersection des types de structures:
// 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
{
...
}L'importation de packages multiples est également possible:
// Package declaration. Offset is 100.
package test offset 100
// Package import
import proto
import protoex
...L'importation de packages est implémentée en utilisant:
Certains fichiers de structures (un ou plusieurs) peuvent être marqués avec l'attribut «[clé]». En conséquence, les opérateurs de comparaison correspondants seront générés qui permettent de comparer deux instances de la structure (égalité, commande, hachage) par des champs marqués. Cette capacité permet d'utiliser la structure comme clé dans la carte associative et les conteneurs de hachage.
L'exemple ci-dessous montre l'utilisation de l'attribut «[key]»:
struct MyKeyStruct
{
[key] int32 uid;
[key] stirng login;
string name;
string address;
}Après la génération de code pour la langue C ++, la classe comparable suivante sera générée:
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); }
...
};Les nombres de type de structure augmentent automatiquement jusqu'à ce que vous le fournissions manuellement. Il y a deux possibilités:
L'exemple ci-dessous montre l'idée:
// 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
{
...
}Les structures peuvent être héritées d'une autre structure. Dans ce cas, tous les champs de la structure de base seront présents chez un enfant.
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;
}Il est également possible de réutiliser le numéro de type de structure de base chez un enfant en utilisant l'opérateur «= base». Il est utile lorsque vous étendez la structure du package importé tiers:
// 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;
}Le versioning est simple avec un encodage binaire rapide.
Supposons que vous avez un protocole 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;
}Vous devez l'étendre avec de nouvelles valeurs d'énumération, de drapeau et de structure. Ajoutez simplement les valeurs requises à la fin des déclarations correspondantes:
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)
}Vous pouvez maintenant sérialiser et désérialiser les structures dans différentes combinaisons:
Si vous n'êtes pas en mesure de modifier un protocole tiers, vous pouvez toujours avoir une solution pour l'étendre. Créez simplement un nouveau protocole et importez-y un tiers. Étendez ensuite les structures avec héritage:
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)
}Si le modèle de domaine compilé avec un indicateur-Sender, le code de protocole de l'expéditeur / récepteur sera généré.
L'interface de l'expéditeur contient des méthodes «Send (struct)» pour toutes les structures du modèle de domaine. Il a également une méthode abstraite `` onzend (données, taille) 'qui doit être implémentée pour envoyer des données sérialisées à une prise, un tuyau, etc.
L'interface du récepteur contient des gestionnaires «onreceive (struct)» pour toutes les structures du modèle de domaine. Il a également une méthode publique «OnReceive (type, données, taille) qui doit être utilisée pour nourrir le récepteur avec des données reçues d'une prise, d'un tuyau, etc.
Voici un exemple d'utilisation du protocole de communication de l'expéditeur / récepteur dans la langue 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 ;
}La sortie est la suivante:
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)])
Tous les repères utilisent le même modèle de domaine pour créer un seul compte avec trois commandes:
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 );Sérialisation Benchmark C ++ Code:
BENCHMARK_FIXTURE (SerializationFixture, " Serialize " )
{
// Reset FBE stream
writer. reset ();
// Serialize the account to the FBE stream
writer. serialize (account);
}Résultats de référence de sérialisation:
| Langue et plate-forme | Taille du message | Taux de sérialisation | Temps de sérialisation |
|---|---|---|---|
| C ++ Win64 | 252 octets | 10 416 667 OPS / S | 96 ns |
| C ++ Win64 (finale) | 152 octets | 16 129 032 OPS / S | 62 ns |
| C ++ Win64 (JSON) | 353 octets | 926 784 OPS / S | 1 079 ns |
| C # win64 | 252 octets | 1 432 665 OPS / S | 698 ns |
| C # win64 (finale) | 152 octets | 1 597 444 OPS / S | 626 ns |
| C # win64 (JSON) | 341 octets | 434 783 OPS / S | 2 300 ns |
| Aller win64 | 252 octets | 2 739 726 OPS / S | 365 ns |
| Go Win64 (finale) | 152 octets | 2 949 852 OPS / S | 339 ns |
| Go Win64 (JSON) | 341 octets | 258 732 OPS / S | 3 865 ns |
| Java win64 | 252 octets | 4 247 162 OPS / S | 236 ns |
| Java Win64 (finale) | 152 octets | 4 883 205 OPS / S | 205 ns |
| Java Win64 (JSON) | 353 octets | 213 983 OPS / S | 4 673 ns |
| Javascript win64 | 252 octets | 93 416 OPS / S | 10 705 ns |
| Javascript Win64 (finale) | 152 octets | 112 665 OPS / S | 8 876 ns |
| Javascript Win64 (JSON) | 341 octets | 217 637 OPS / S | 4 595 ns |
| Kotlin win64 | 252 octets | 3 546 694 OPS / S | 282 ns |
| Kotlin Win64 (finale) | 152 octets | 4 096 406 OPS / S | 244 ns |
| Kotlin Win64 (JSON) | 353 octets | 185 788 OPS / S | 5 382 ns |
| Python win64 | 252 octets | 9 434 OPS / S | 105 999 ns |
| Python Win64 (finale) | 152 octets | 11 635 OPS / S | 85 945 ns |
| Python Win64 (JSON) | 324 octets | 61 737 OPS / S | 16 198 NS |
| Ruby Win64 | 252 octets | 23 013 OPS / S | 43 453 ns |
| Ruby Win64 (finale) | 152 octets | 33 361 OPS / S | 29 975 NS |
| Ruby Win64 (JSON) | 353 octets | 50 842 OPS / S | 19 669 ns |
| MacOS rapide | 252 octets | 74 002 OPS / S | 13 513 NS |
| Swift macOS (final) | 152 octets | 100 755 OPS / S | 9 925 ns |
| Swift MacOS (JSON) | 353 octets | 18 534 OPS / S | 53 953 ns |
Désérialisation Benchmark C ++ Code:
BENCHMARK_FIXTURE (DeserializationFixture, " Deserialize " )
{
// Deserialize the account from the FBE stream
reader. deserialize (deserialized);
}Résultats de référence de désérialisation:
| Langue et plate-forme | Taille du message | Taux de désérialisation | Temps de désérialisation |
|---|---|---|---|
| C ++ Win64 | 252 octets | 9 523 810 OPS / S | 105 ns |
| C ++ Win64 (finale) | 152 octets | 10 989 011 OPS / S | 91 ns |
| C ++ Win64 (JSON) | 353 octets | 1 375 516 OPS / S | 727 ns |
| C # win64 | 252 octets | 1 014 199 OPS / S | 986 ns |
| C # win64 (finale) | 152 octets | 1 607 717 OPS / S | 622 ns |
| C # win64 (JSON) | 341 octets | 258 532 OPS / S | 3 868 ns |
| Aller win64 | 252 octets | 1 510 574 OPS / S | 662 ns |
| Go Win64 (finale) | 152 octets | 1 540 832 OPS / S | 649 ns |
| Go Win64 (JSON) | 341 octets | 251 825 OPS / S | 3 971 NS |
| Java win64 | 252 octets | 2 688 084 OPS / S | 372 ns |
| Java Win64 (finale) | 152 octets | 3 036 020 OPS / S | 329 ns |
| Java Win64 (JSON) | 353 octets | 308 675 OPS / S | 3 240 ns |
| Javascript win64 | 252 octets | 133 892 OPS / S | 7 469 ns |
| Javascript Win64 (finale) | 152 octets | 292 273 OPS / S | 3 422 ns |
| Javascript Win64 (JSON) | 341 octets | 289 417 OPS / S | 3 455 ns |
| Kotlin win64 | 252 octets | 2 280 923 OPS / S | 438 ns |
| Kotlin Win64 (finale) | 152 octets | 2 652 728 OPS / S | 277 NS |
| Kotlin Win64 (JSON) | 353 octets | 250 524 OPS / S | 3 992 ns |
| Python win64 | 252 octets | 8 305 OPS / S | 120 411 ns |
| Python Win64 (finale) | 152 octets | 11 661 OPS / S | 85 758 ns |
| Python Win64 (JSON) | 324 octets | 48 859 OPS / S | 20 467 ns |
| Ruby Win64 | 252 octets | 24 351 OPS / S | 41 066 ns |
| Ruby Win64 (finale) | 152 octets | 33 555 OPS / S | 29 802 ns |
| Ruby Win64 (JSON) | 353 octets | 42 860 OPS / S | 23 331 ns |
| MacOS rapide | 252 octets | 86 288 OPS / S | 11 589 ns |
| Swift macOS (final) | 152 octets | 10 3519 OPS / S | 9 660 ns |
| Swift MacOS (JSON) | 353 octets | 17 077 OPS / S | 58 558 ns |
Vérifiez le code C ++ Benchmark:
BENCHMARK_FIXTURE (VerifyFixture, " Verify " )
{
// Verify the account
model. verify ();
}Vérifiez les résultats de référence:
| Langue et plate-forme | Taille du message | Vérifier le taux | Vérifiez le temps |
|---|---|---|---|
| C ++ Win64 | 252 octets | 31 250 000 OPS / S | 32 ns |
| C ++ Win64 (finale) | 152 octets | 35 714 286 OPS / S | 28 ns |
| C # win64 | 252 octets | 4 504 505 OPS / S | 222 ns |
| C # win64 (finale) | 152 octets | 8 064 516 OPS / S | 124 ns |
| Aller win64 | 252 octets | 8 474 576 OPS / S | 118 ns |
| Go Win64 (finale) | 152 octets | 9 090 909 OPS / S | 110 ns |
| Java win64 | 252 octets | 11 790 374 OPS / S | 85 ns |
| Java Win64 (finale) | 152 octets | 16 205 533 OPS / S | 62 ns |
| Javascript win64 | 252 octets | 1 105 627 OPS / S | 905 ns |
| Javascript Win64 (finale) | 152 octets | 5 700 408 OPS / S | 175 ns |
| Kotlin win64 | 252 octets | 8 625 935 OPS / S | 116 ns |
| Kotlin Win64 (finale) | 152 octets | 13 373 757 OPS / S | 75 ns |
| Python win64 | 252 octets | 20 825 OPS / S | 48 019 ns |
| Python Win64 (finale) | 152 octets | 23 590 OPS / S | 42 391 ns |
| Ruby Win64 | 252 octets | 57 201 OPS / S | 17 482 ns |
| Ruby Win64 (finale) | 152 octets | 74 262 OPS / S | 13 466 ns |
| MacOS rapide | 252 octets | 164 446 OPS / S | 6 081 ns |
| Swift macOS (final) | 152 octets | 228 154 OPS / S | 4 383 ns |