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
实施深度静态分析完全不值得,因为它会完全优化您的简单代码。
我查看了另一个关于 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
实施深度静态分析完全不值得,因为它会完全优化您的简单代码。