【发布时间】:2022-07-27 03:17:04
【问题描述】:
我知道std::function 是用 type erasure 习惯用法实现的。类型擦除是一种方便的技术,但作为一个缺点,它需要在堆上存储底层对象的寄存器(某种数组)。
因此,在创建或复制 function 对象时需要进行分配,因此该过程应该比简单地将函数作为模板类型进行操作要慢。
为了检查这个假设,我运行了一个测试函数,它累积 n = cycles 连续整数,然后将总和除以增量数 n。
首先编码为模板:
#include <iostream>
#include <functional>
#include <chrono>
using std::cout;
using std::function;
using std::chrono::system_clock;
using std::chrono::duration_cast;
using std::chrono::milliseconds;
double computeMean(const double start, const int cycles) {
double tmp(start);
for (int i = 0; i < cycles; ++i) {
tmp += i;
}
return tmp / cycles;
}
template<class T>
double operate(const double a, const int b, T myFunc) {
return myFunc(a, b);
}
还有main.cpp:
int main()
{
double init(1), result;
int increments(1E9);
// start clock
system_clock::time_point t1 = system_clock::now();
result = operate(init, increments, computeMean);
// stop clock
system_clock::time_point t2 = system_clock::now();
cout << "Input: " << init << ", " << increments << ", Output: " << result << '\n';
cout << "Time elapsed: " << duration_cast<milliseconds>(t2 - t1).count() << " ms\n";
return 0;
}
这运行了一百次,平均结果为10024.9 ms。
然后我在main中引入function对象,加上operate的模板特化,这样上面的代码就可以循环使用了:
// as above, just add the template specialization
template<>
double operate(const double a, const int b, function<double (const double, const int)> myFunc) {
cout << "nontemplate called\n";
return myFunc(a, b);
}
// and inside the main
int main()
{
//...
// start clock
system_clock::time_point t1 = system_clock::now();
// new lines
function<double (const double, const int)> computeMean =
[](const double init, const int increments) {
double tmp(init);
for (int i = 0; i < increments; ++i) {
tmp += i;
}
return tmp / increments;
};
// rest as before
// ...
}
我预计function 版本会更快,但平均速度差不多,实际上甚至更慢,result = 9820.3 ms。
检查标准差,它们大致相同,1233.77 与 1234.96。
这有什么意义?我原以为带有function 对象的第二个版本会比模板版本慢。
Here整个测试可以在GDB上运行。
【问题讨论】:
-
你是如何编译你的程序的?特别是启用了哪些优化?智能优化器可以转换您的代码以呈现差异,没有任何优化可以告诉我们任何性能。
-
我使用了
-O2。当然会涉及到编译器优化,我想在主要问题中提到它但后来忘记了。 -
查看您的两个程序生成的程序集。它们可能是相同的。
-
这有什么意义?我的第一个猜测是:你的假设不正确。
标签: c++ c++11 templates functional-programming function-object