- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要解析一个包含金融 FIX 协议(protocol)的文件。示例如下:
1128=99=24535=X49=CME75=2017040934=82452=2017040920070508394791460=201704092007050800000005799=10000000268=2279=0269=B48=900655=ESM783=23271=1473460731=100000005796=17263279=0269=C48=900655=ESM783=24271=2861528731=100000005796=1726310=219
我的应用程序将加载许多文件,每个文件都有数百万行历史数据,因此需要考虑性能。
我已经在线查看了有关 FIX 解析的类似问题,并探索了 QuickFix 库(特别是使用 FIX::Message(string) 来破解消息),但我的目标是获得比我能够实现的更好的吞吐量使用 quickfix。
我为最常见的消息类型(市场数据增量刷新)编写了一个模拟,以查看我所达到的速度,并且对每秒约 60,000 条消息的结果最不满意,包括文件解析一个 3m 的线文件。
这是我的第一个 C++ 应用程序,所以我预计我的方法会有很多缺陷,如果您能提出任何关于如何提高其性能的建议,我们将不胜感激。
目前流程是file->string->MDIncrementalRefresh。 MDIncrementalRefresh 有两个可选的重复组,我使用 vector 来存储它们,因为它们在消息之间的大小未知。
我猜我在每次更新时重建 MDIncrementalRefresh 与我通过更新之前的 MDIncrementalRefresh 的内容重新使用该对象相比会导致不必要的开销吗?
提前致谢
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
using namespace std;
std::vector<std::string> string_split(std::string s, const char delimiter)
{
size_t start=0;
size_t end=s.find_first_of(delimiter);
std::vector<std::string> output;
while (end <= std::string::npos)
{
output.emplace_back(s.substr(start, end-start));
if (end == std::string::npos)
break;
start=end+1;
end = s.find_first_of(delimiter, start);
}
return output;
}
const char FIX_FIELD_DELIMITER = '\x01';
const char FIX_KEY_DELIMITER = '=';
const int STR_TO_CHAR = 0;
const int KEY = 0;
const int VALUE = 1;
const string Field_TransactTime = "60";
const string Field_MatchEventIndicator = "5799";
const string Field_NoMDEntries = "268";
const string Field_MDUpdateAction = "279";
const string Field_MDEntryType = "269";
const string Field_SecurityID = "48";
const string Field_RptSeq = "83";
const string Field_MDEntryPx = "270";
const string Field_MDEntrySize = "271";
const string Field_NumberOfOrders = "346";
const string Field_MDPriceLevel = "1023";
const string Field_OpenCloseSettlFlag = "286";
const string Field_AggressorSide = "5797";
const string Field_TradingReferenceDate = "5796";
const string Field_HighLimitPrice = "1149";
const string Field_LowLimitPrice = "1148";
const string Field_MaxPriceVariation = "1143";
const string Field_ApplID = "1180";
const string Field_NoOrderIDEntries = "37705";
const string Field_OrderID = "37";
const string Field_LastQty = "32";
const string Field_SettlPriceType= "731";
class OrderIdEntry {
public:
string OrderID;
int LastQty;
};
struct MDEntry {
public:
// necessary for defaults?
char MDUpdateAction;
char MDEntryType;
int SecurityID;
int RptSeq;
double MDEntryPx;
int MDEntrySize;
int NumberOfOrders = 0;
int MDPriceLevel = 0;
int OpenCloseSettlFlag = 0;
string SettlPriceType = "";
int AggressorSide = 0;
string TradingReferenceDate = "";
double HighLimitPrice = 0.0;
double LowLimitPrice = 0.0;
double MaxPriceVariation = 0.0;
int ApplID = 0;
};
class MDIncrementalRefresh {
public:
string TransactTime;
string MatchEventIndicator;
int NoMDEntries;
int NoOrderIDEntries = 0;
vector<MDEntry> MDEntries;
vector<OrderIdEntry> OrderIdEntries;
MDIncrementalRefresh(const string& message)
{
MDEntry* currentMDEntry = nullptr;
OrderIdEntry* currentOrderIDEntry = nullptr;
for (auto fields : string_split(message, FIX_FIELD_DELIMITER))
{
vector<string> kv = string_split(fields, FIX_KEY_DELIMITER);
// Header :: MDIncrementalRefresh
if (kv[KEY] == Field_TransactTime) this->TransactTime = kv[VALUE];
else if (kv[KEY] == Field_MatchEventIndicator) this->MatchEventIndicator = kv[VALUE];
else if (kv[KEY] == Field_NoMDEntries) this->NoMDEntries = stoi(kv[VALUE]);
else if (kv[KEY] == Field_NoOrderIDEntries) this->NoOrderIDEntries = stoi(kv[VALUE]);
// Repeating Group :: MDEntry
else if (kv[KEY] == Field_MDUpdateAction)
{
MDEntries.push_back(MDEntry());
currentMDEntry = &MDEntries.back(); // use pointer for fast lookup on subsequent repeating group fields
currentMDEntry->MDUpdateAction = kv[VALUE][STR_TO_CHAR];
}
else if (kv[KEY] == Field_MDEntryType) currentMDEntry->MDEntryType = kv[VALUE][STR_TO_CHAR];
else if (kv[KEY] == Field_SecurityID) currentMDEntry->SecurityID = stoi(kv[VALUE]);
else if (kv[KEY] == Field_RptSeq) currentMDEntry->RptSeq = stoi(kv[VALUE]);
else if (kv[KEY] == Field_MDEntryPx) currentMDEntry->MDEntryPx = stod(kv[VALUE]);
else if (kv[KEY] == Field_MDEntrySize) currentMDEntry->MDEntrySize = stoi(kv[VALUE]);
else if (kv[KEY] == Field_NumberOfOrders) currentMDEntry->NumberOfOrders = stoi(kv[VALUE]);
else if (kv[KEY] == Field_MDPriceLevel) currentMDEntry->MDPriceLevel = stoi(kv[VALUE]);
else if (kv[KEY] == Field_OpenCloseSettlFlag) currentMDEntry->OpenCloseSettlFlag = stoi(kv[VALUE]);
else if (kv[KEY] == Field_SettlPriceType) currentMDEntry->SettlPriceType= kv[VALUE];
else if (kv[KEY] == Field_AggressorSide) currentMDEntry->AggressorSide = stoi(kv[VALUE]);
else if (kv[KEY] == Field_TradingReferenceDate) currentMDEntry->TradingReferenceDate = kv[VALUE];
else if (kv[KEY] == Field_HighLimitPrice) currentMDEntry->HighLimitPrice = stod(kv[VALUE]);
else if (kv[KEY] == Field_LowLimitPrice) currentMDEntry->LowLimitPrice = stod(kv[VALUE]);
else if (kv[KEY] == Field_MaxPriceVariation) currentMDEntry->MaxPriceVariation = stod(kv[VALUE]);
else if (kv[KEY] == Field_ApplID) currentMDEntry->ApplID = stoi(kv[VALUE]);
// Repeating Group :: OrderIDEntry
else if (kv[KEY] == Field_OrderID) {
OrderIdEntries.push_back(OrderIdEntry());
currentOrderIDEntry = &OrderIdEntries.back();
currentOrderIDEntry->OrderID = kv[VALUE];
}
else if (kv[KEY] == Field_LastQty) currentOrderIDEntry->LastQty = stol(kv[VALUE]);
}
}
};
int main() {
//std::string filename = "test/sample";
std::string line;
std::ifstream file (filename);
int count = 0;
if (file.is_open())
{
while ( std::getline( file, line ) )
{
MDIncrementalRefresh md(line);
if (md.TransactTime != "") {
count++;
}
}
file.close();
}
cout << count << endl;
return 0;
}
最佳答案
对于那些感兴趣的人来说,处理上面代码的大部分时间都花在了 split_string 函数上。对 split_string 的大量调用导致在堆上进行许多(昂贵的)分配。
另一种实现 split_string_optim 重新使用预分配的 vector 。这可以防止在每次 split_string 函数调用时不必要的堆分配/扩展。以下运行 1.5m 迭代的示例表明速度提高了 3.4 倍。通过利用本身不会将分配的内存释放回堆的 vector.clear(),它可以确保后续对 split_string_optim 的 split_string 调用,其中生成的 vector 大小 <= 先前没有额外分配。
#include <string>
#include <vector>
void string_split_optim(std::vector<std::string>& output, const std::string &s, const char delimiter)
{
output.clear();
size_t start = 0;
size_t end = s.find_first_of(delimiter);
while (end <= std::string::npos)
{
output.emplace_back(s.substr(start, end - start));
if (end == std::string::npos)
break;
start = end + 1;
end = s.find_first_of(delimiter, start);
}
}
int main()
{
const int NUM_RUNS = 1500000;
const std::string s = "1128=9\u00019=174\u000135=X\u000149=CME\u000175=20170403\u000134=1061\u000152=20170402211926965794928\u000160=20170402211926965423233\u00015799=10000100\u0001268=1\u0001279=1\u0001269=1\u000148=9006\u000155=ESM7\u000183=118\u0001270=236025.0\u0001271=95\u0001346=6\u00011023=9\u000110=088\u0001";
std::vector<std::string> vec;
// standard
clock_t tStart = clock();
for (int i = 0; i < NUM_RUNS; ++i)
{
vec = string_split(s, '=');
}
printf("Time taken: %.2fs\n", (double) (clock() - tStart) / CLOCKS_PER_SEC);
// reused vector
tStart = clock();
for (int i = 0; i < NUM_RUNS; ++i)
{
string_split_optim(vec, s, '=');
vec.clear();
}
printf("Time taken: %.2fs\n", (double) (clock() - tStart) / CLOCKS_PER_SEC);
}
我的 macbook 上的结果是提高了 3.4 倍。
Time taken: 6.60s
Time taken: 1.94s
此外,MDIncrementalRefresh 对象被重复构造(在堆栈上,但它的 vector 成员也在堆上扩展)。根据上述关于 split_string 的发现,我决定重新使用临时对象并简单地清除其先前的状态,从而导致另一个显着的性能提升。
关于c++ - 高效解析FIX消息c++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43391615/
我一直在使用 AJAX 从我正在创建的网络服务中解析 JSON 数组时遇到问题。我的前端是一个简单的 ajax 和 jquery 组合,用于显示从我正在创建的网络服务返回的结果。 尽管知道我的数据库查
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我在尝试运行 Android 应用程序时遇到问题并收到以下错误 java.lang.NoClassDefFoundError: com.parse.Parse 当我尝试运行该应用时。 最佳答案 在这
有什么办法可以防止etree在解析HTML内容时解析HTML实体吗? html = etree.HTML('&') html.find('.//body').text 这给了我 '&' 但我想
我有一个有点疯狂的例子,但对于那些 JavaScript 函数作用域专家来说,它看起来是一个很好的练习: (function (global) { // our module number one
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 8 年前。 Improve th
我需要编写一个脚本来获取链接并解析链接页面的 HTML 以提取标题和其他一些数据,例如可能是简短的描述,就像您链接到 Facebook 上的内容一样。 当用户向站点添加链接时将调用它,因此在客户端启动
在 VS Code 中本地开发时,包解析为 C:/Users//AppData/Local/Microsoft/TypeScript/3.5/node_modules/@types//index而不是
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我被赋予了将一种语言“翻译”成另一种语言的工作。对于使用正则表达式的简单逐行方法来说,源代码过于灵活(复杂)。我在哪里可以了解更多关于词法分析和解析器的信息? 最佳答案 如果你想对这个主题产生“情绪化
您好,我在解析此文本时遇到问题 { { { {[system1];1;1;0.612509325}; {[system2];1;
我正在为 adobe after effects 在 extendscript 中编写一些代码,最终变成了 javascript。 我有一个数组,我想只搜索单词“assemble”并返回整个 jc3_
我有这段代码: $(document).ready(function() { // }); 问题:FB_RequireFeatures block 外部的代码先于其内部的代码执行。因此 who
背景: netcore项目中有些服务是在通过中间件来通信的,比如orleans组件。它里面服务和客户端会指定网关和端口,我们只需要开放客户端给外界,服务端关闭端口。相当于去掉host,这样省掉了些
1.首先贴上我试验成功的代码 复制代码 代码如下: protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。 你可以通过本站学习 X
【PHP代码】 复制代码 代码如下: $stmt = mssql_init('P__Global_Test', $conn) or die("initialize sto
在SQL查询分析器执行以下代码就可以了。 复制代码代码如下: declare @t varchar(255),@c varchar(255) declare table_cursor curs
前言 最近练习了一些前端算法题,现在做个总结,以下题目都是个人写法,并不是标准答案,如有错误欢迎指出,有对某道题有新的想法的友友也可以在评论区发表想法,互相学习🤭 题目 题目一: 二维数组中的
我是一名优秀的程序员,十分优秀!