std::function 与模板相比的性能

std::function performance as compared to templates

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

#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)

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

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


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

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