การเข้ารหัสแบบไบนารีอย่างรวดเร็วช่วยให้สามารถอธิบายโมเดลโดเมนวัตถุธุรกิจโครงสร้างข้อมูลที่ซับซ้อนคำขอและการตอบสนองของลูกค้า/เซิร์ฟเวอร์และสร้างรหัสดั้งเดิมสำหรับภาษาการเขียนโปรแกรมและแพลตฟอร์มที่แตกต่างกัน
เอกสารการเข้ารหัสแบบไบนารีอย่างรวดเร็ว
ดาวน์โหลดการเข้ารหัสแบบไบนารีอย่างรวดเร็ว
ข้อกำหนดการเข้ารหัสแบบไบนารีอย่างรวดเร็ว
การเปรียบเทียบประสิทธิภาพกับโปรโตคอลอื่น ๆ สามารถพบได้ที่นี่:
| โปรโตคอล | ขนาดข้อความ | เวลาการทำให้เป็นอนุกรม | เวลา deserialization |
|---|---|---|---|
| cap'n'proto | 208 ไบต์ | 558 ns | 359 ns |
| การเข้ารหัสแบบ fastbinaryencod | 234 ไบต์ | 66 ns | 82 ns |
| นักทำนาย | 280 ไบต์ | 830 ns | 290 ns |
| Protobuf | 120 ไบต์ | 628 ns | 759 ns |
| JSON | 301 ไบต์ | 740 ns | 500 ns |
เวิร์กโฟลว์การใช้งานทั่วไปมีดังต่อไปนี้:
ตัวอย่างโครงการ:
ไม่จำเป็น:
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ในการใช้การเข้ารหัสแบบไบนารีอย่างรวดเร็วคุณควรจัดทำโมเดลโดเมน (ออบเจ็กต์ธุรกิจที่เรียกว่า) โมเดลโดเมนคือชุดของ enums ธงและโครงสร้างที่เกี่ยวข้องกันและอาจรวมกันในลำดับชั้นบางอย่าง
ข้อกำหนดรูปแบบการเข้ารหัสแบบไบนารีแบบเร็ว (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 แก้ปัญหาการกำหนดเวอร์ชันโปรโตคอล
ทำตามขั้นตอนด้านล่างเพื่อให้เป็นอนุกรมวัตถุโดเมนใด ๆ :
ทำตามขั้นตอนด้านล่างเพื่อ deserialize วัตถุโดเมนใด ๆ :
นี่คือ exmple ของการทำให้เป็นอนุกรม 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)
]
)
เป็นไปได้ที่จะบรรลุความเร็วในการทำให้เป็นอนุกรมมากขึ้นหากโปรโตคอลของคุณเติบโตพอสมควรเพื่อให้คุณสามารถแก้ไขเวอร์ชันสุดท้ายและปิดการใช้งานเวอร์ชันซึ่งต้องใช้ขนาดและเวลาเพิ่มเติมในการประมวลผล
| โปรโตคอล | ขนาดข้อความ | เวลาการทำให้เป็นอนุกรม | เวลา deserialization | ตรวจสอบเวลา |
|---|---|---|---|---|
| fbe | 252 ไบต์ | 88 ns | 98 ns | 33 ns |
| fbe สุดท้าย | 152 ไบต์ | 57 ns | 81 ns | 28 ns |
โมเดลโดเมนสุดท้ายสามารถรวบรวมได้ด้วยธงสุดท้าย เนื่องจากผลลัพธ์เพิ่มเติมรุ่นสุดท้ายจะพร้อมใช้งานสำหรับการทำให้เป็นอนุกรม
ทำตามขั้นตอนด้านล่างเพื่อให้เป็นอนุกรมวัตถุโดเมนใด ๆ ในรูปแบบสุดท้าย:
ทำตามขั้นตอนด้านล่างเพื่อ deserialize วัตถุโดเมนใด ๆ :
นี่คือการทำให้เป็นอนุกรมสุดท้ายของ 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 Flag รหัสการจัดลำดับ JSON จะถูกสร้างขึ้นในวัตถุโดเมนทั้งหมด เป็นผลให้แต่ละวัตถุโดเมนสามารถทำให้เป็นอนุกรม/deserialized ในรูปแบบ/จากรูปแบบ 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)
]
)
แพ็คเกจจะถูกประกาศด้วยชื่อแพ็คเกจและ structs ชดเชย (ไม่บังคับ) ออฟเซ็ตจะถูกเพิ่มในประเภทโครงสร้างที่เพิ่มขึ้นหากไม่ได้ให้ชัดเจน
นี่คือตัวอย่างของการประกาศแพ็คเกจง่าย ๆ :
// 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
{
...
}แพ็คเกจหนึ่งสามารถนำเข้าสู่อีกแพ็คเกจและ enums ธงและโครงสร้างทั้งหมดสามารถนำกลับมาใช้ใหม่ในแพ็คเกจปัจจุบัน แพคเกจชดเชยถูกใช้ที่นี่เพื่อหลีกเลี่ยงประเภทโครงสร้างทางแยก:
// 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]' เนื่องจากผลลัพธ์ที่สอดคล้องกันของตัวดำเนินการเปรียบเทียบจะถูกสร้างขึ้นซึ่งอนุญาตให้เปรียบเทียบสองอินสแตนซ์ของ struct (ความเท่าเทียมการสั่งซื้อการแฮช) โดยฟิลด์ที่ทำเครื่องหมายไว้ ความสามารถนี้ช่วยให้สามารถใช้โครงสร้างเป็นคีย์ในแผนที่เชื่อมโยงและคอนเทนเนอร์แฮช
ตัวอย่างด้านล่างแสดงให้เห็นถึงการใช้แอตทริบิวต์ '[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 ใหม่ธงและค่าโครงสร้าง เพียงเพิ่มค่าที่ต้องการในตอนท้ายของการประกาศที่เกี่ยวข้อง:
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)
}ตอนนี้คุณสามารถทำให้เป็นอนุกรมและ deserialize structs ในชุดค่าผสมที่แตกต่างกัน:
หากคุณไม่สามารถแก้ไขโปรโตคอลของบุคคลที่สามได้คุณยังสามารถแก้ปัญหาในการขยายได้ เพียงสร้างโปรโตคอลใหม่และนำเข้าบุคคลที่สามเข้ามา จากนั้นขยายโครงสร้างด้วยการสืบทอด:
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)
}หากโมเดลโดเมนที่คอมไพล์ -ตั้งค่าสถานะ -ตัวเลือกรหัสโปรโตคอลผู้ส่ง/ตัวรับสัญญาณจะถูกสร้างขึ้น
อินเตอร์เฟสผู้ส่งมีวิธีการ 'ส่ง (struct)' สำหรับโครงสร้างโมเดลโดเมนทั้งหมด นอกจากนี้ยังมีวิธีการที่เป็นนามธรรม 'onsend (data, size)' ซึ่งควรนำไปใช้เพื่อส่งข้อมูลอนุกรมไปยังซ็อกเก็ตท่อ ฯลฯ
อินเทอร์เฟซตัวรับสัญญาณประกอบด้วยตัวจัดการ 'onreceive (struct)' สำหรับโครงสร้างโมเดลโดเมนทั้งหมด นอกจากนี้ยังมีวิธีการ 'onreceive (ประเภทข้อมูลขนาด)' ซึ่งควรใช้ในการป้อนข้อมูลที่ได้รับจากซ็อกเก็ตท่อ ฯลฯ
นี่คือ exmple ของการใช้โปรโตคอลการสื่อสารผู้ส่ง/ตัวรับสัญญาณในภาษา 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 ns |
| C ++ Win64 (สุดท้าย) | 152 ไบต์ | 16 129 032 OPS/S | 62 ns |
| C ++ Win64 (JSON) | 353 ไบต์ | 926 784 OPS/S | 1 079 ns |
| c# win64 | 252 ไบต์ | 1 432 665 OPS/S | 698 ns |
| c# win64 (สุดท้าย) | 152 ไบต์ | 1 597 444 OPS/S | 626 ns |
| C# Win64 (JSON) | 341 ไบต์ | 434 783 OPS/S | 2 300 ns |
| ไป win64 | 252 ไบต์ | 2 739 726 OPS/S | 365 ns |
| Go Win64 (สุดท้าย) | 152 ไบต์ | 2 949 852 OPS/S | 339 ns |
| Go Win64 (JSON) | 341 ไบต์ | 258 732 ops/s | 3 865 ns |
| Java Win64 | 252 ไบต์ | 4 247 162 OPS/S | 236 ns |
| Java Win64 (สุดท้าย) | 152 ไบต์ | 4 883 205 OPS/S | 205 ns |
| Java Win64 (JSON) | 353 ไบต์ | 213 983 ops/s | 4 673 NS |
| JavaScript Win64 | 252 ไบต์ | 93 416 OPS/S | 10 705 ns |
| JavaScript Win64 (สุดท้าย) | 152 ไบต์ | 112 665 OPS/S | 8 876 NS |
| JavaScript Win64 (JSON) | 341 ไบต์ | 217 637 OPS/S | 4 595 ns |
| Kotlin Win64 | 252 ไบต์ | 3 546 694 OPS/S | 282 ns |
| Kotlin Win64 (สุดท้าย) | 152 ไบต์ | 4 096 406 OPS/S | 244 ns |
| Kotlin Win64 (JSON) | 353 ไบต์ | 185 788 OPS/S | 5 382 ns |
| Python Win64 | 252 ไบต์ | 9 434 ops/s | 105 999 NS |
| Python Win64 (สุดท้าย) | 152 ไบต์ | 11 635 ops/s | 85 945 ns |
| Python Win64 (JSON) | 324 ไบต์ | 61 737 OPS/S | 16 198 NS |
| Ruby Win64 | 252 ไบต์ | 23 013 ops/s | 43 453 NS |
| Ruby Win64 (สุดท้าย) | 152 ไบต์ | 33 361 OPS/S | 29 975 NS |
| Ruby Win64 (JSON) | 353 ไบต์ | 50 842 ops/s | 19 669 NS |
| macos อย่างรวดเร็ว | 252 ไบต์ | 74 002 ops/s | 13 513 NS |
| Swift MacOS (สุดท้าย) | 152 ไบต์ | 100 755 ops/s | 9 925 ns |
| Swift MacOS (JSON) | 353 ไบต์ | 18 534 OPS/S | 53 953 NS |
มาตรฐาน Deserialization C ++ รหัส:
BENCHMARK_FIXTURE (DeserializationFixture, " Deserialize " )
{
// Deserialize the account from the FBE stream
reader. deserialize (deserialized);
}ผลการวัดผล Deserialization:
| ภาษาและแพลตฟอร์ม | ขนาดข้อความ | อัตรา deserialization | เวลา deserialization |
|---|---|---|---|
| C ++ Win64 | 252 ไบต์ | 9 523 810 OPS/S | 105 ns |
| C ++ Win64 (สุดท้าย) | 152 ไบต์ | 10 989 011 OPS/S | 91 ns |
| C ++ Win64 (JSON) | 353 ไบต์ | 1 375 516 OPS/S | 727 ns |
| c# win64 | 252 ไบต์ | 1 014 199 OPS/S | 986 ns |
| c# win64 (สุดท้าย) | 152 ไบต์ | 1 607 717 OPS/S | 622 ns |
| C# Win64 (JSON) | 341 ไบต์ | 258 532 OPS/S | 3 868 ns |
| ไป win64 | 252 ไบต์ | 1 510 574 OPS/S | 662 ns |
| Go Win64 (สุดท้าย) | 152 ไบต์ | 1 540 832 OPS/S | 649 ns |
| Go Win64 (JSON) | 341 ไบต์ | 251 825 ops/s | 3 971 NS |
| Java Win64 | 252 ไบต์ | 2 688 084 OPS/S | 372 ns |
| Java Win64 (สุดท้าย) | 152 ไบต์ | 3 036 020 ops/s | 329 ns |
| Java Win64 (JSON) | 353 ไบต์ | 308 675 OPS/S | 3 240 ns |
| JavaScript Win64 | 252 ไบต์ | 133 892 ops/s | 7 469 NS |
| JavaScript Win64 (สุดท้าย) | 152 ไบต์ | 292 273 ops/s | 3 422 ns |
| JavaScript Win64 (JSON) | 341 ไบต์ | 289 417 OPS/S | 3 455 ns |
| Kotlin Win64 | 252 ไบต์ | 2 280 923 OPS/S | 438 ns |
| Kotlin Win64 (สุดท้าย) | 152 ไบต์ | 2 652 728 OPS/S | 277 NS |
| Kotlin Win64 (JSON) | 353 ไบต์ | 250 524 OPS/S | 3 992 ns |
| Python Win64 | 252 ไบต์ | 8 305 ops/s | 120 411 NS |
| Python Win64 (สุดท้าย) | 152 ไบต์ | 11 661 OPS/S | 85 758 NS |
| Python Win64 (JSON) | 324 ไบต์ | 48 859 OPS/S | 20 467 NS |
| Ruby Win64 | 252 ไบต์ | 24 351 OPS/S | 41 066 NS |
| Ruby Win64 (สุดท้าย) | 152 ไบต์ | 33 555 OPS/S | 29 802 ns |
| Ruby Win64 (JSON) | 353 ไบต์ | 42 860 OPS/S | 23 331 NS |
| macos อย่างรวดเร็ว | 252 ไบต์ | 86 288 ops/s | 11 589 NS |
| Swift MacOS (สุดท้าย) | 152 ไบต์ | 10 3519 OPS/S | 9 660 ns |
| Swift MacOS (JSON) | 353 ไบต์ | 17 077 ops/s | 58 558 NS |
ตรวจสอบมาตรฐาน C ++ รหัส:
BENCHMARK_FIXTURE (VerifyFixture, " Verify " )
{
// Verify the account
model. verify ();
}ตรวจสอบผลลัพธ์มาตรฐาน:
| ภาษาและแพลตฟอร์ม | ขนาดข้อความ | ตรวจสอบอัตรา | ตรวจสอบเวลา |
|---|---|---|---|
| C ++ Win64 | 252 ไบต์ | 31 250 000 OPS/S | 32 ns |
| C ++ Win64 (สุดท้าย) | 152 ไบต์ | 35 714 286 OPS/S | 28 ns |
| c# win64 | 252 ไบต์ | 4 504 505 OPS/S | 222 ns |
| c# win64 (สุดท้าย) | 152 ไบต์ | 8 064 516 OPS/S | 124 ns |
| ไป win64 | 252 ไบต์ | 8 474 576 OPS/S | 118 ns |
| Go Win64 (สุดท้าย) | 152 ไบต์ | 9 090 909 OPS/S | 110 ns |
| Java Win64 | 252 ไบต์ | 11 790 374 OPS/S | 85 ns |
| Java Win64 (สุดท้าย) | 152 ไบต์ | 16 205 533 OPS/S | 62 ns |
| JavaScript Win64 | 252 ไบต์ | 1 105 627 OPS/S | 905 ns |
| JavaScript Win64 (สุดท้าย) | 152 ไบต์ | 5 700 408 OPS/S | 175 ns |
| Kotlin Win64 | 252 ไบต์ | 8 625 935 OPS/S | 116 ns |
| Kotlin Win64 (สุดท้าย) | 152 ไบต์ | 13 373 757 OPS/S | 75 ns |
| Python Win64 | 252 ไบต์ | 20 825 ops/s | 48 019 ns |
| Python Win64 (สุดท้าย) | 152 ไบต์ | 23 590 OPS/S | 42 391 NS |
| Ruby Win64 | 252 ไบต์ | 57 201 ops/s | 17 482 NS |
| Ruby Win64 (สุดท้าย) | 152 ไบต์ | 74 262 ops/s | 13 466 NS |
| macos อย่างรวดเร็ว | 252 ไบต์ | 164 446 OPS/S | 6 081 ns |
| Swift MacOS (สุดท้าย) | 152 ไบต์ | 228 154 ops/s | 4 383 NS |