为什么多次调用时C++ lambda比普通函数慢?

37

我刚刚尝试比较了C++11中lambda表达式的性能,所以我做了一个测试--计算一个double类型向量中元素的总和。下面是实现代码:

#include <vector>
#include <algorithm>
#include <iostream>
#include <ctime>

#define LOG(x) { std::cout << #x << " = " << (x) << "\n"; }
#define TIME(t) { std::cout << ((double)(clock() - (t)) / CLOCKS_PER_SEC) << " s\n"; }

double sum(const std::vector<double>& v)
{
    double s = 0.0;
    for (auto i = v.cbegin(); i != v.cend(); ++i)
        s += *i;
    return s;
}

int main()
{
    const size_t MAX = 1; // number of tests
    const size_t SIZE = 100000000; // length of the vector

    std::vector<double> v(SIZE, 1.0);
    double out;

    clock_t clk;

    std::cout << "iterator\n";

    clk = clock();
    out = 0.0;
    for (size_t i = 0; i < MAX; ++i)
        out += sum(v);
    TIME(clk)
    LOG(out)

    std::cout << "\nlambda\n";

    clk = clock();
    out = 0.0;
    for (size_t i = 0; i < MAX; ++i)
        std::for_each(v.cbegin(), v.cend(), [&](double d) { out += d; });
    TIME(clk)
    LOG(out)

    return 0;
}

这个程序的结果如下(在VS2010 SP1中编译,Release模式):

迭代器
0.32秒
输出 = 1e+008

lambda表达式
0.326秒
输出 = 1e+008

可以看出,性能几乎没有差别。然而,如果我将MAX的值设为10(这意味着将执行10次求和而不是一次),结果就会有所不同:

迭代器
0.287秒
输出 = 1e+009

lambda表达式
2.84秒
输出 = 1e+009

lambda表达式的测试时间大约是迭代器的10倍。为什么?我认为可能是因为每次迭代都会创建新的lambda表达式,但当我尝试了这个方法之后:

out = 0.0;
auto f = [&](double d) { out += d; };
for (size_t i = 0; i < MAX; ++i)
    std::for_each(v.cbegin(), v.cend(), f);

结果没有改变。有人能解释一下这种行为吗?

3
非常有趣!你能否尝试在手写循环中使用 lambda 替代 foreach - Sergey Kalinichenko
在Linux上,g++ 4.6.2的运行时间完全相同(在我的电脑上为0.13-0.12秒)。 - Cubbi
没有更多的谜团,看看我的编辑。虽然是我的错误,但我仍然觉得它非常有趣。 :) - Archie
你应该将你的编辑作为一个答案添加,并接受它以供他人参考。 - anthonyvd
1个回答

65

事实证明,这不是与lambda表达式有关的问题,而是编译器通过缓存sum()函数的结果来优化了第一个循环。

在将第一个循环改为以下形式后:

out = 0.0;
for (size_t i = 0; i < MAX; ++i)
{
    out += sum(v);
    v[i] = 1.0; // this adds O(1) time and prevents caching
}

在这两种情况下,时间大致相等,但 lambda 更受青睐。


14
故事的寓意是--在测试和基准测试时,始终使用真正的代码,而不是玩具代码。 - David Schwartz
3
@Archie 你也在lambda中加入了v[i] = 1.0吗? - sprite

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接