【发布时间】:2015-11-02 12:49:24
【问题描述】:
我创建了一个测试程序,在解析 csv 数据时测量 std::regex 的性能:
#include <string.h>
#include <iostream>
#include <stdexcept>
#include <chrono>
#include <regex>
#include <set>
#include <iomanip>
#define DEFAULT_REGEX \
R"(^((?:[^\x00-\x1F\x80-\xFF\\;]|\\\\|\\;)*);)" \
R"((L|P|D|DN|R|W|LS|PS|RS|LU|PU|RU|LK|PK|RK|F);)" \
R"(((?:[^\x00-\x1F\x80-\xFF\\;]|\\\\|\\;)*);)" \
R"(((?:[^\x00-\x1F\x80-\xFF\\;]|\\\\|\\;)*);)" \
R"(((?:[^\x00-\x1F\x80-\xFF\\;]|\\\\|\\;|\\:)*))" \
R"((?:;((?:[^\x00-\x1F\x80-\xFF\\;])" \
R"(|\\\\|\\;|\';\')*))?$)"
struct results_t {
std::string address;
std::string command;
std::string client;
std::string param;
std::string value;
std::string error;
};
void std_regex(std::size_t num, const std::string &str, results_t &res) {
std::smatch pieces;
static const std::regex pattern{DEFAULT_REGEX};
for (auto i = 0u; i < num; i++) {
bool matched = std::regex_match(str, pieces, pattern);
if (!(matched && pieces.size() == 7)) {
throw std::runtime_error("ERROR");
}
}
res.address = pieces[1];
res.command = pieces[2];
res.client = pieces[3];
res.param = pieces[4];
res.value = pieces[5];
res.error = pieces[6];
}
std::size_t get_median(const std::multiset<std::size_t> &measured_values) {
std::size_t i = 0;
std::size_t median = 0;
for (auto it = measured_values.cbegin();; it++, i++) {
double tmp = static_cast<double>(measured_values.size() - 1) / 2.0;
if (i == floor(tmp)) {
median = *it;
}
if (i == ceil(tmp)) {
median += *it;
break;
}
}
return static_cast<std::size_t>(static_cast<double>(median) / 2.0 + 0.5);
}
std::size_t get_avg(const std::multiset<std::size_t> &measured_values) {
return static_cast<std::size_t>(
std::accumulate(measured_values.cbegin(), measured_values.cend(), 0) /
static_cast<double>(measured_values.size()) +
0.5);
}
int main(void) {
constexpr std::size_t num = 100000;
constexpr std::size_t measure_num = 250;
std::string str = "zzz\\\\bbbb;L;babaa;bubu\\;cc;vvvv;asdff";
std::multiset<std::size_t> measured_values;
results_t res;
for (std::size_t i = 0; i < measure_num; i++) {
auto start = std::chrono::system_clock::now();
std_regex(num, str, res);
auto end = std::chrono::system_clock::now();
measured_values.insert(
std::chrono::duration_cast<std::chrono::microseconds>(end - start)
.count());
}
std::cout << *measured_values.cbegin() << ";" // min
<< *measured_values.crbegin() << ";" /// max
<< get_avg(measured_values) << ";" // average
<< get_median(measured_values) << std::endl; // median
}
使用 Ubuntu 15.10 和 Debian 8,编译代码(没有错误或警告):
clang++-3.4 -DCOMPILER='"clang++-3.4"' -Wall -pedantic-errors -Werror -Wextra -DNDEBUG -O3 -mtune=native -march=native -std=c++1y -o eval_clang_3_4 eval.cpp
正如预期的那样,如果使用不同的编译器,这个程序会显示不同的时间。例如。如果你使用 g++5.2 而不是 g++4.9,性能会变得更好。
但是这个评估程序也显示了一个有趣的特性:如果你在 Debian 8 而不是 Ubuntu 15.10 上使用 clang++-3.4,它会产生更糟糕的时间。该软件在同一台机器上运行两次(Intel i7-3770k 和 8GB RAM),在这两种情况下,都使用了 clang++-3.4。
评估执行了 250 次,在以下几行中,您可以看到此测量的统计信息。
这是 Debian 8 上的测量值:(min;max;avg;median)
691244;1160628;713112;700739
以下是 Ubuntu 15.10 上的测量值:(min;max;avg;median)
198484;290986;202656;200637
我不关心这个,如果差异大约是 10% 或 20%,但在这种情况下,差异大约是 350%。
为什么在执行这个二进制文件时会有这么大的不同?
【问题讨论】:
-
看起来
error的正则表达式是(具有讽刺意味的)错误的。它有......奇怪的括号。你真的是说(|\\|\;|';')*吗? (答案:没有) -
不正则表达式没有错,左边的括号包含到R"(
-
我知道。你错过了我的意思。
-
如果您有兴趣,我有一个更易于维护且速度更快的替代实现:stackoverflow-sehe.s3.amazonaws.com/…
标签: c++ regex parsing ubuntu debian