std::bind vs lambda performance
std::bind vs lambda performance
我想为几个函数的执行计时,我给自己写了一个助手:
using namespace std;
template<int N = 1, class Fun, class... Args>
void timeExec(string name, Fun fun, Args... args) {
auto start = chrono::steady_clock::now();
for(int i = 0; i < N; ++i) {
fun(args...);
}
auto end = chrono::steady_clock::now();
auto diff = end - start;
cout << name << ": "<< chrono::duration<double, milli>(diff).count() << " ms. << endl;
}
我想用这种方式计时成员函数,我必须使用bind或lambda,我想看看哪个对性能的影响更小,所以我这样做了:
const int TIMES = 10000;
timeExec<TIMES>("Bind evaluation", bind(&decltype(result)::eval, &result));
timeExec<1>("Lambda evaluation", [&]() {
for(int i = 0; i < TIMES; ++i) {
result.eval();
}
});
结果如下:
Bind evaluation: 0.355158 ms.
Lambda evaluation: 0.014414 ms.
我不知道内部原理,但我认为lambda不可能比bind好。我能想到的唯一合理的解释是编译器在lambda循环中优化了后续的函数求值。
你怎么解释?
我假设lambda不可能比bind好。
你真是先入为主。
Lambdas被绑定到编译器内部,因此可能会发现额外的优化机会。此外,它们的设计是为了避免效率低下。
然而,这里可能没有发生编译器优化技巧。罪魁祸首可能是绑定的参数bind(&decltype(result)::eval, &result)
。您正在传递一个指向成员函数的指针(PTMF)和一个对象。与lambda类型不同,PTMF不会捕获实际调用的函数;它只包含函数签名(参数和返回类型)。慢循环使用间接分支函数调用,因为编译器无法通过常量传播解析函数指针。
如果将成员eval()
重命名为operator () ()
并去掉bind
,则显式对象的行为本质上就像lambda一样,性能差异应该会消失。
我已经测试过了。我的结果表明,Lambda实际上比bind快。
这是代码(请不要看样式):
#include <iostream>
#include <functional>
#include <chrono>
using namespace std;
using namespace chrono;
using namespace placeholders;
typedef void SumDataBlockEventHandler(uint8_t data[], uint16_t len);
class SpeedTest {
uint32_t sum = 0;
uint8_t i = 0;
void SumDataBlock(uint8_t data[], uint16_t len) {
for (i = 0; i < len; i++) {
sum += data[i];
}
}
public:
function<SumDataBlockEventHandler> Bind() {
return bind(&SpeedTest::SumDataBlock, this, _1, _2);
}
function<SumDataBlockEventHandler> Lambda() {
return [this](auto data, auto len)
{
SumDataBlock(data, len);
};
}
};
int main()
{
SpeedTest test;
function<SumDataBlockEventHandler> testF;
uint8_t data[] = { 0,1,2,3,4,5,6,7 };
#if _DEBUG
const uint32_t testFcallCount = 1000000;
#else
const uint32_t testFcallCount = 100000000;
#endif
uint32_t callsCount, whileCount = 0;
auto begin = high_resolution_clock::now();
auto end = begin;
while (whileCount++ < 10) {
testF = test.Bind();
begin = high_resolution_clock::now();
callsCount = 0;
while (callsCount++ < testFcallCount)
testF(data, 8);
end = high_resolution_clock::now();
cout << testFcallCount << " calls of binded function: " << duration_cast<nanoseconds>(end - begin).count() << "ns" << endl;
testF = test.Lambda();
begin = high_resolution_clock::now();
callsCount = 0;
while (callsCount++ < testFcallCount)
testF(data, 8);
end = high_resolution_clock::now();
cout << testFcallCount << " calls of lambda function: " << duration_cast<nanoseconds>(end - begin).count() << "ns" << endl << endl;
}
system("pause");
}
控制台结果(优化版本):
100000000 calls of binded function: 1846298524ns
100000000 calls of lambda function: 1048086461ns
100000000 calls of binded function: 1259759880ns
100000000 calls of lambda function: 1032256243ns
100000000 calls of binded function: 1264817832ns
100000000 calls of lambda function: 1039052353ns
100000000 calls of binded function: 1263404007ns
100000000 calls of lambda function: 1031216018ns
100000000 calls of binded function: 1275305794ns
100000000 calls of lambda function: 1041313446ns
100000000 calls of binded function: 1256565304ns
100000000 calls of lambda function: 1031961675ns
100000000 calls of binded function: 1248132135ns
100000000 calls of lambda function: 1033890224ns
100000000 calls of binded function: 1252277130ns
100000000 calls of lambda function: 1042336736ns
100000000 calls of binded function: 1250320869ns
100000000 calls of lambda function: 1046529458ns
我在Visual Studio Enterprise 2015下以完全优化(/Ox)的发布模式和禁用优化的调试模式编译了它。结果证实lambda比我的笔记本电脑(戴尔Inspiron 7537,英特尔酷睿i7-4510U 2.00GHz, 8GB RAM)上的bind更快。
有人能在你的电脑上验证这一点吗?
相关文章:
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 可组合的lambda/std::函数与std::可选
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 如何将lambda作为模板类的成员函数参数
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- 在 lambda 捕获中声明的变量的类型推导
- 我可以将调用类的"this"传递给 lambda 函数吗?
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- 模板函数指针和lambda
- 两组使用lambda函数的大括号
- 使lambda不可复制/不可移动
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 尝试将lambda函数放在队列中时出现一般分配器错误(可能是与unique_ptr有关的错误)
- 将带有unique_ptr的可变 lambda 传递给 const&std::function
- AWS Lambda C++运行时权限被拒绝
- 捕获lambda中的std::数组
- 这 4 个 lambda 表达式之间有什么区别?
- 在实现文件中使用头文件的通用 lambda
- std::bind vs lambda performance