在其他函数或循环中构造 lambda 时是不是存在性能问题?

Posted

技术标签:

【中文标题】在其他函数或循环中构造 lambda 时是不是存在性能问题?【英文标题】:Are there performance concerns when constructing lambdas inside other functions or loops?在其他函数或循环中构造 lambda 时是否存在性能问题? 【发布时间】:2019-04-16 18:19:21 【问题描述】:

javascript 中,Mozilla recommends 如果不需要闭包,则不应在其他函数中创建函数,因为这会对脚本性能产生负面影响。在 JavaScript 中,同样的问题也适用于在循环内创建函数时。同样的问题是否适用于 C++ lambda?

例如,这两个函数之间是否存在性能差异:

int f1(vector<int> v) 
    for_each(v.begin(), v.end(), [](int i)  cout << i << endl; );


auto print_int = [](int i)  cout << i << endl; ;
int f2(vector<int> v) 
    for_each(v.begin(), v.end(), print_int);

我认为是的,这些担忧适用于 C++,并且f2 的性能将优于f1;但是,我一直没能找到明确的答案。

【问题讨论】:

大多数 lambdas(包括这个)都是微不足道的结构,因此任何体面的编译器都会完全省略构造。 与其他语言不同,所有这些东西都在编译时得到优化。 Lambda 实际上只是语法糖。如果您真的很担心,那么您可以使用this 对其进行基准测试 【参考方案1】:

不,是的。

对于简单的 lambda,没关系。这是因为 lambda 是带有 operator() 的类的简单简写。

相关元素是该类具有构造函数。想象一下:

std::map<std::string, std::string> m = create();
auto lambda = [m]()  /* code */ ;

在循环中执行此捕获没有意义,因为您复制了许多不应更改的字符串。 在这种情况下,通过引用捕获也可能有意义。

我的建议是:和其他班级一样。如果想构建,只需将其放在您认为合乎逻辑的地方。如果建造成本高昂,请想想为什么这么贵,并在可能的情况下考虑将其移出。

【讨论】:

【参考方案2】:

不,现实生活中的编译器不会有性能差异,因为 C++ 编译器可能会为这两个函数生成完全相同的汇编代码。

通常,您不应将专为脚本语言设计的指南应用于编译语言,因为它们在编译阶段发生的事情(因此与运行时性能无关)与运行时发生的事情有很大不同。

【讨论】:

【参考方案3】:

这取决于编译器,或者更确切地说,它的优化器。

如果发现它可以内联print_int,那么f1()f2()的性能将是相同的。

如果没有,那么 f2() 可能会生成一个实际的函数调用(即 x86 汇编器中的 CALL),而 f1() 可能会内联代码以避免函数调用。

但是,在任何情况下,每次传递都创建“lambda”是极不可能的。 Lambda 只是具有重载函数调用运算符的本地类对象的语法糖。

【讨论】:

我还没有看到编译器内联第一个版本,但不是第二个,反之亦然。 @SergeyA 我也是,但这是可能的。在一些编译器和优化级别上,我确实在生成的代码中发现了一些差异。尽管我在 for_each() 而不是 lambda 本身的优化(缺乏)方面有所不同。【参考方案4】:

不,我希望您的代码中的两个示例都不会改变速度。这两个语句对于编译器来说非常相似。

此外,就性能而言,lambda 可能是一个非常危险的构造。根据整个构造,编译器可以或多或少地优化函数调用。使用类似于函数指针的 lambda 会给您带来灾难性的性能结果,例如使用 std::function 作为 lambda 函数指针的包装器(例如 What is the performance overhead of std::function?)

【讨论】:

以上是关于在其他函数或循环中构造 lambda 时是不是存在性能问题?的主要内容,如果未能解决你的问题,请参考以下文章

lambda表达式

SpringBoot 循环依赖

用于检查特定标签是不是不存在的 Lambda 函数-python

在循环中使用多个模型时,tensorflow 或 python 是不是存在内存清理问题?

5Lambda表达式

java8新特性→方法和构造函数引用:替代Lambda表达式