Nik*_*iou 23 c++ boost stl c++11
我试图选择一种将积分转换为字符串的标准方法,所以我接着通过测量3种方法的执行时间进行了一次小的性能评估
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <chrono>
#include <random>
#include <exception>
#include <type_traits>
#include <boost/lexical_cast.hpp>
using namespace std;
// 1. A way to easily measure elapsed time -------------------
template<typename TimeT = std::chrono::milliseconds>
struct measure
{
template<typename F>
static typename TimeT::rep execution(F const &func)
{
auto start = std::chrono::system_clock::now();
func();
auto duration = std::chrono::duration_cast< TimeT>(
std::chrono::system_clock::now() - start);
return duration.count();
}
};
// -----------------------------------------------------------
// 2. Define the convertion functions ========================
template<typename T> // A. Using stringstream ================
string StringFromNumber_SS(T const &value) {
stringstream ss;
ss << value;
return ss.str();
}
template<typename T> // B. Using boost::lexical_cast =========
string StringFromNumber_LC(T const &value) {
return boost::lexical_cast<string>(value);
}
template<typename T> // C. Using c++11 to_string() ===========
string StringFromNumber_C11(T const &value) {
return std::to_string(value);
}
// ===========================================================
// 3. A wrapper to measure the different executions ----------
template<typename T, typename F>
long long MeasureExec(std::vector<T> const &v1, F const &func)
{
return measure<>::execution([&]() {
for (auto const &i : v1) {
if (func(i) != StringFromNumber_LC(i)) {
throw std::runtime_error("FAIL");
}
}
});
}
// -----------------------------------------------------------
// 4. Machinery to generate random numbers into a vector -----
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type
FillVec(vector<T> &v)
{
std::mt19937 e2(1);
std::uniform_int_distribution<> dist(3, 1440);
std::generate(v.begin(), v.end(), [&]() { return dist(e2); });
}
template<typename T>
typename std::enable_if<!std::is_integral<T>::value>::type
FillVec(vector<T> &v)
{
std::mt19937 e2(1);
std::uniform_real_distribution<> dist(-1440., 1440.);
std::generate(v.begin(), v.end(), [&]() { return dist(e2); });
}
// -----------------------------------------------------------
int main()
{
std::vector<int> v1(991908);
FillVec(v1);
cout << "C++ 11 method ......... " <<
MeasureExec(v1, StringFromNumber_C11<int>) << endl;
cout << "String stream method .. " <<
MeasureExec(v1, StringFromNumber_SS<int>) << endl;
cout << "Lexical cast method ... " <<
MeasureExec(v1, StringFromNumber_LC<int>) << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
甲典型的输出(在VS2013至极运行释放意味着/ O2 optimizaiton标志).将
C++ 11方法......... 273
字符串流方法.. 1923年
词汇演员方法...... 222
g++ -std=c++11 -Ofast -march=native -Wall -pedantic main.cpp && ./a.out
Run Code Online (Sandbox Code Playgroud)
C++ 11方法......... 414
字符串流方法.. 1538
词汇演员方法...... 275
免责声明:结果将相互比较,而不是跨机器
1.为什么字符串流方法始终是最差的(按一个数量级)?如果更快的替代方案出现,它是否应被视为已被弃用?
2.为什么词汇演员一直是最好的?我们可以假设这是最快的实现吗?
请随意调整并使用此代码的版本.我很感激您对该主题的见解.
实际运行的代码只有一个测量值main()
.这里共有3个人一起出现以节省空间.
优化标志是编译器特定的或应用程序强制的.我只是提供代码块来执行测试,并期望SO用户将结果或建议插入每个编译器的最佳配置(为此我提供了这里使用的标志值).
所述代码适用于任何数值到字符串的转换(它需要改变的类型v1
中main
).sehe做了double
(在他的回答评论中提到).玩这个也是个好主意.
seh*_*ehe 31
问题1.为什么字符串流方法始终是最差的?
经典错误:每次都创建一个新的字符串流
template<typename T> // 1. Using stringstream
string StringFromIntegral_SS(T const &value) {
thread_local stringstream ss;
ss.str("");
ss.clear();
ss << value;
return ss.str();
}
Run Code Online (Sandbox Code Playgroud)
问题2.为什么词汇演员一直是最好的?我们可以假设这是最快的实现吗?
因为它最专业; 并且,不,存在更快的实现.据我所知,FastFormat和Boost Spirit有竞争力的产品.
更新 Boost精神Karma仍然很容易击败一堆:
template<typename T> // 4. Karma to string
std::string StringFromIntegral_K(T const &value) {
thread_local auto const gen = boost::spirit::traits::create_generator<T>::call();
thread_local char buf[20];
char* it = buf;
boost::spirit::karma::generate(it, gen, value);
return std::string(buf, it);
}
Run Code Online (Sandbox Code Playgroud)
时序:
C++ 11 method 111
String stream method 103
Lexical cast method 57
Spirit Karma method 36
Spirit Karma method with string_ref 13
Run Code Online (Sandbox Code Playgroud)
为了boost::string_ref
减少分配,使用版本的速度要快得多:
template<typename T> // 5. Karma to string_ref
boost::string_ref StringFromIntegral_KSR(T const &value) {
thread_local auto const gen = boost::spirit::traits::create_generator<T>::call();
thread_local char buf[20];
char* it = buf;
boost::spirit::karma::generate(it, gen, value);
return boost::string_ref(buf, it-buf);
}
Run Code Online (Sandbox Code Playgroud)
我使用断言测试循环测试了所有修改过的方法的正确性:
return measure<>::execution(
//[&]() { for (auto const &i : v1) { func(i); }});
[&]() { for (auto const &i : v1) { assert(func(i) == StringFromIntegral_LC(i)); }});
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3300 次 |
最近记录: |