【问题标题】:std::function performance as compared to templates [duplicate]与模板相比的 std::function 性能[重复]
【发布时间】:2015-12-21 04:55:08
【问题描述】:

我查看了另一个关于 std::function 的堆栈溢出问题以及为什么它很慢,但我仍然不相信/不明白。我从问题中运行了程序,并进行了一些修改。

#include <iostream>
#include <functional>
#include <string>
#include <chrono>

template <typename F>
float calc1(F f) { return -1.0f * f(3.3f) + 666.0f; }

float calc2(const std::function<float (float)>& f) { return -1.0f * f(3.3f) + 666.0f; }
int main() {

    std::function<float (float)> f = [](float arg){ return arg * 0.5f; };
    for (int i = 0; i < 1e9; ++i) {
        // calc2(f);
        calc1([](float arg){ return arg * 0.5f; });
    }

    return 0;
}

使用模板版本,代码运行时间为 4 秒,但涉及 std::function 的运行时间增加到 15 秒。我理解为什么复制一个 std::function 会很昂贵,但是在这里即使传递了一个引用,似乎也没有什么区别,有人可以解释为什么会发生这种情况吗?

仅供参考,这是我输入 g++ --version 时的输出

Apple LLVM version 7.0.2 (clang-700.1.81)

【问题讨论】:

  • 您是否在打开优化的情况下进行编译?
  • 是的,启用优化后,常规代码只需要 0.4 秒,我假设根本没有执行任何操作,因为代码中的其他地方没有依赖关系,但是使用 std::function 运行时变为 1.9 秒
  • @NirFriedman:这是不同的。 std::function 不仅仅是一个函子。它使用类型擦除,这是一个显着的区别。
  • @Cornstalk 的标题只是误导,问题是关于 std::function。接受的答案(我的,完全公开)深入比较 std:: 函数和 lambda,甚至查看生成的程序集。
  • @NirFriedman:该死。好吧,至少现在你已经获得了 >2k 的代表,所以你不应该再有这个问题了 :)

标签: c++ templates c++11 c++14 std-function


【解决方案1】:

当我编译你的程序(使用-O3优化)并使用calc1时,执行时间是0.0秒。这是因为编译器可以完全优化掉代码。它知道你的代码实际上并没有任何事情,所以运行它没有任何意义。

当我编译您的程序(再次使用 -O3 优化)并使用 calc2(使用 std::function)时,程序需要 2 秒才能运行。之所以需要更长的时间是因为优化器无法优化所有内容。 std::function 在运行时工作(不是编译时,因为它必须执行类型擦除;参见this questionthis question),通常优化器不能内联(或完全优化掉) ) 通过std::function 的调用(在这种情况下,优化器在技术上可以这样做,因为这是一个简单的程序,但事实并非如此)。


std::function 调用不能被内联的原因是编译器并不总是知道std::function 会做什么。在这段代码中,编译器的静态分析器非常简单,如果它足够“智能”的话,它实际上可以内联整个内容,然后将其优化掉。

但这在编译器中实现可能是一件棘手的事情,而且在更复杂的“真实”程序中并没有太大的区别。在更复杂的程序中,实际上不可能知道std::function 会做什么。例如,假设您有第二个.cpp 文件调用calc2,而不同 std::function。或者想象一下,如果您将 std::function 设置为两个不同的 lambda 之一,具体取决于用户输入。在程序运行之前,编译器不会知道实际调用哪个 lambda,因此它不能只是优化所有内容。由于此类问题,为std::function 实施深度静态分析将完全优化您的简单代码并不值得。

【讨论】:

  • 谢谢!我看了第二个链接,我似乎仍然不明白。为什么编译器无法优化掉函数调用?
  • @Curious:我尝试添加一些扩展信息。如果您仍有疑问,请告诉我。
  • @downvoter:我同意你投反对票,但你能否发表评论,以便我们都了解我的回答有什么问题/不好?
  • 我根本没有投反对票!我真的很喜欢你的回答:)
  • 从你所说的和我的理解来看也是如此。实际上可以在编译时对其进行优化,但是静态分析太难了,不能被认为是要实现的东西,对吧?我不知道在某些情况下这是否被认为是不可能的
猜你喜欢
  • 1970-01-01
  • 2013-01-18
  • 2012-12-27
  • 2012-04-17
  • 1970-01-01
  • 2018-06-06
  • 2012-04-23
  • 2011-04-07
相关资源
最近更新 更多