【问题标题】:Why C++ lambda is slower than ordinary function when called multiple times?为什么 C++ lambda 在多次调用时比普通函数慢?
【发布时间】:2011-12-23 02:48:24
【问题描述】:

我只是尝试比较 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 拉姆达 0.326 秒 出 = 1e+008

正如大家所见,性能几乎没有差异。但是,如果我将 MAX 的值设为 10(这意味着求和将执行 10 次而不是 1 次),结果会有所不同:

迭代器 0.287 秒 出 = 1e+009 拉姆达 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);

结果没有改变。有人可以向我解释这种行为吗?

【问题讨论】:

  • 这很有趣!您可以尝试在手写循环中使用 lambda 而不是 foreach
  • g++ 4.6.2 on linux 提供完全相同的运行时间(在我的计算机上为 0.13 - 0.12 s)
  • 没有更多的谜团,检查我的编辑。我的错误,但我仍然觉得它很有趣。 :)
  • 您应该将您的编辑添加为答案并接受它以供其他人将来参考。
  • 我这样做了,谢谢你的建议。

标签: c++ performance lambda c++11


【解决方案1】:

事实证明,这不是 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。

【讨论】:

  • 故事的寓意——始终使用真实代码进行测试和基准测试,绝不使用玩具代码。
  • @Archie 您是否也将 v[i] = 1.0 添加到 lambda 中?
猜你喜欢
  • 2014-12-19
  • 1970-01-01
  • 2012-06-02
  • 2014-02-20
  • 2016-02-13
  • 2010-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多