我看了另一个关于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)
当我编译程序(进行-O3
优化)并使用时calc1
,执行时间为0.0秒。这是因为编译器可以完全优化代码。它知道您的代码实际上没有执行任何操作,因此运行任何代码都没有意义。
当我编译程序(再次进行-O3
优化)并使用calc2
(使用std::function
)时,程序需要2秒钟才能运行。之所以需要更长的时间,是因为优化器无法优化所有内容。std::function
在运行时工作(而不是编译时,因为它必须进行类型擦除;请参见此问题和此问题),并且通常,优化器无法内联(或完全优化掉)进行的调用std::function
(在这种情况下,从技术上讲优化程序可以这样做,因为这是一个简单的程序,但事实并非如此。
std::function
无法内联调用的原因是因为编译器并不总是知道std::function
会做什么。在这段代码中,如果编译器的静态分析器足够“聪明”,则可以对其进行内联然后对其进行优化,这很简单。
但这在编译器中实现起来可能是一件棘手的事情,而且在更复杂的“实际”程序中并没有太大的区别。在更复杂的程序中,实际上不可能知道std::function
会做什么。例如,假设您有另一个.cpp
文件调用calc2
了different std::function
。或想象一下,是否std::function
根据用户输入将其设置为两个不同的lambda之一。直到程序运行,编译器才知道实际要调用哪个lambda,因此它不能仅仅优化所有内容。由于存在此类问题,因此完全不必std::function
优化简单的代码就不值得进行深度静态分析。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句