c++lambda表达式的效率问题

jian_vv 2015-11-02 11:41:43
float test()
{
return 333 * 2.43;
}

for (size_t i = 0; i < 10000000; i++)
{
test();
}

for (size_t i = 0; i < 10000000; i++)
{
auto f = []()->float{return 333 * 2.43; };
f();
}

我这样测出来2者效率居然不相上下(一千万次循环lambda表达式那个只慢了不到5毫秒),我觉得不科学,是不是编译器优化了我的测试代码,不然每次循环都要多一次定义,效率怎么会都不落下,
你们觉得呢
...全文
780 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
dustpg 2015-11-03
  • 打赏
  • 举报
回复
引用 1 楼 dustpg 的回复:
我以前也以为c++11的lambda就是一个函数指针, 所以存在效率问题. 然后发现实际是个functor, 效率是绝对的.
而且比一般functor的限制高, 更加容易优化, 现在写代码简直轻松多了.
dustpg 2015-11-03
  • 打赏
  • 举报
回复
引用 7 楼 jian_vv 的回复:
[quote=引用 1 楼 dustpg 的回复:] 我以前也以为c++11的lambda就是一个函数指针, 所以存在效率问题. 然后发现实际是个functor, 效率是绝对的.
你的意思是编译期,就把这个函数编译好了?[/quote] 那lz认为的效率低是什么原因呢, 我认为效率低是因为是函数指针, 所以不能被内联, 作为比较函数像是std::sort参数, 效率会很低, 比如C语言的fsort传递的是函数指针, 效率比C++的std::sort差不多要慢上1倍.
dustpg 2015-11-03
  • 打赏
  • 举报
回复
我以前也以为c++11的lambda就是一个函数指针, 所以存在效率问题. 然后发现实际是个functor, 效率是绝对的.
fefe82 2015-11-03
  • 打赏
  • 举报
回复
引用 12 楼 jian_vv 的回复:
[quote=引用 9 楼 fefe82 的回复:] [quote=引用 6 楼 jian_vv 的回复:] [quote=引用 5 楼 fefe82 的回复:]

$ cat test.cpp
#include <cstdlib>
float test()
{
    return 333 * 2.43;
}
int main(int, const char **)
{
    for (size_t i = 0; i < 10000000; i++)
    {
        test();
    }

    for (size_t i = 0; i < 10000000; i++)
    {
        auto f = []()->float {return 333 * 2.43; };
        f();
    }
    return 0;
}

$ g++ --std=c++11 --pedantic -g -O2 test.cpp
$ g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ objdump -d a.out > a.ss
a.ss

0000000000400400 <main>:
  400400:   31 c0                   xor    %eax,%eax
  400402:   c3                      retq
优化之后 main 只剩了一句 return 0;
我去。。。怎样才能测试得到真实的结果呢,但是我跑的时候确实经过几百毫秒啊[/quote] 那估计你没有开优化。 不过测效率不开优化没有什么意义。 ================== int test() { return rand(); } int n = 0; for (size_t i = 0; i < 10000000; i++) { n ^= test(); } printf ("%d\n", n); 这个应该不会被优化掉,不过两个地方应该都会被直接内联,不会有任何区别。[/quote] 恩,我之前那个是debug模式,不过这个要切确测试出来lambda表达式效率还真难。 我是在一个渲染循环中经常使用到swap函数,才想到lambda表示会不会降效率[/quote] 那你就在实际场景下实测。用你的实际编译优化选项。 不过如果你已经遇到效率问题,建议找个 profiler 测试热点,而不是这样猜测。 如果没有遇到效率问题,那就不用管它。
jian_vv 2015-11-03
  • 打赏
  • 举报
回复
引用 9 楼 fefe82 的回复:
[quote=引用 6 楼 jian_vv 的回复:] [quote=引用 5 楼 fefe82 的回复:]

$ cat test.cpp
#include <cstdlib>
float test()
{
    return 333 * 2.43;
}
int main(int, const char **)
{
    for (size_t i = 0; i < 10000000; i++)
    {
        test();
    }

    for (size_t i = 0; i < 10000000; i++)
    {
        auto f = []()->float {return 333 * 2.43; };
        f();
    }
    return 0;
}

$ g++ --std=c++11 --pedantic -g -O2 test.cpp
$ g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ objdump -d a.out > a.ss
a.ss

0000000000400400 <main>:
  400400:   31 c0                   xor    %eax,%eax
  400402:   c3                      retq
优化之后 main 只剩了一句 return 0;
我去。。。怎样才能测试得到真实的结果呢,但是我跑的时候确实经过几百毫秒啊[/quote] 那估计你没有开优化。 不过测效率不开优化没有什么意义。 ================== int test() { return rand(); } int n = 0; for (size_t i = 0; i < 10000000; i++) { n ^= test(); } printf ("%d\n", n); 这个应该不会被优化掉,不过两个地方应该都会被直接内联,不会有任何区别。[/quote] 恩,我之前那个是debug模式,不过这个要切确测试出来lambda表达式效率还真难。 我是在一个渲染循环中经常使用到swap函数,才想到lambda表示会不会降效率
赵4老师 2015-11-03
  • 打赏
  • 举报
回复
理解讨论之前请先学会如何观察! 计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程! 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步Debug版对应汇编一行! 单步Debug版对应汇编千行不如单步Release版对应汇编一行! VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。) 无profiler不要谈效率!!尤其在这个云计算、虚拟机、模拟器、CUDA、多核 、多级cache、指令流水线、多种存储介质、……满天飞的时代!
fefe82 2015-11-03
  • 打赏
  • 举报
回复

#include <cstdlib>
#include <cstdio>
int test()
{
    return rand();
}
int main(int, const char **)
{
    int n = 0;
    for (size_t i = 0; i < 10000000; i++)
    {
        n ^= test();
    }
    printf("%d\n", n);

    for (size_t i = 0; i < 10000000; i++)
    {
        auto f = []()->int {return rand(); };
        n ^= f();
    }
    printf("%d\n", n);
    return 0;
}

$ g++ --std=c++11 --pedantic -g -O2 test.cpp
$ g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

00000000004004b0 <main>:
  4004b0:   55                      push   %rbp
  4004b1:   53                      push   %rbx
  4004b2:   bd 80 96 98 00          mov    $0x989680,%ebp
  4004b7:   31 db                   xor    %ebx,%ebx
  4004b9:   48 83 ec 08             sub    $0x8,%rsp
  4004bd:   0f 1f 00                nopl   (%rax)
  4004c0:   e8 db ff ff ff          callq  4004a0 <rand@plt>
  4004c5:   31 c3                   xor    %eax,%ebx
  4004c7:   48 83 ed 01             sub    $0x1,%rbp
  4004cb:   75 f3                   jne    4004c0 <main+0x10>
  4004cd:   89 da                   mov    %ebx,%edx
  4004cf:   be b4 06 40 00          mov    $0x4006b4,%esi
  4004d4:   bf 01 00 00 00          mov    $0x1,%edi
  4004d9:   31 c0                   xor    %eax,%eax
  4004db:   bd 80 96 98 00          mov    $0x989680,%ebp
  4004e0:   e8 ab ff ff ff          callq  400490 <__printf_chk@plt>
  4004e5:   0f 1f 00                nopl   (%rax)
  4004e8:   e8 b3 ff ff ff          callq  4004a0 <rand@plt>
  4004ed:   31 c3                   xor    %eax,%ebx
  4004ef:   48 83 ed 01             sub    $0x1,%rbp
  4004f3:   75 f3                   jne    4004e8 <main+0x38>
  4004f5:   89 da                   mov    %ebx,%edx
  4004f7:   be b4 06 40 00          mov    $0x4006b4,%esi
  4004fc:   bf 01 00 00 00          mov    $0x1,%edi
  400501:   31 c0                   xor    %eax,%eax
  400503:   e8 88 ff ff ff          callq  400490 <__printf_chk@plt>
  400508:   48 83 c4 08             add    $0x8,%rsp
  40050c:   31 c0                   xor    %eax,%eax
  40050e:   5b                      pop    %rbx
  40050f:   5d                      pop    %rbp
  400510:   c3                      retq
两个循环体是一样的 callq (rand), xor, sub, jne 。 4004c0 - 4004cb 4004e8 - 4004f3
  • 打赏
  • 举报
回复
cl test /FAs
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.23026.0 

include listing.inc

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC	?test@@YAMXZ					; test
PUBLIC	main
PUBLIC	__real@444a4c29
EXTRN	_fltused:DWORD
pdata	SEGMENT
$pdata$main DD	imagerel $LN9
	DD	imagerel $LN9+128
	DD	imagerel $unwind$main
pdata	ENDS
;	COMDAT __real@444a4c29
CONST	SEGMENT
__real@444a4c29 DD 0444a4c29r			; 809.19
CONST	ENDS
xdata	SEGMENT
$unwind$main DD	020e01H
	DD	0700a720eH
xdata	ENDS
; Function compile flags: /Odtp
;	COMDAT ??R<lambda_a063bd16e7642c22fd3d9fd00722fd02>@@QEBAMXZ
_TEXT	SEGMENT
this$ = 8
??R<lambda_a063bd16e7642c22fd3d9fd00722fd02>@@QEBAMXZ PROC ; <lambda_a063bd16e7642c22fd3d9fd00722fd02>::operator(), COMDAT

; 15   :         auto f = []()->float {return 333 * 2.43; };

	mov	QWORD PTR [rsp+8], rcx
	movss	xmm0, DWORD PTR __real@444a4c29
	ret	0
??R<lambda_a063bd16e7642c22fd3d9fd00722fd02>@@QEBAMXZ ENDP ; <lambda_a063bd16e7642c22fd3d9fd00722fd02>::operator()
_TEXT	ENDS
; Function compile flags: /Odtp
_TEXT	SEGMENT
$T1 = 32
f$2 = 33
i$3 = 40
i$4 = 48
__formal$ = 80
__formal$ = 88
main	PROC

; 7    : {

$LN9:
	mov	QWORD PTR [rsp+16], rdx
	mov	DWORD PTR [rsp+8], ecx
	push	rdi
	sub	rsp, 64					; 00000040H

; 8    :     for (size_t i = 0; i < 10000000; i++)

	mov	QWORD PTR i$3[rsp], 0
	jmp	SHORT $LN4@main
$LN2@main:
	mov	rax, QWORD PTR i$3[rsp]
	inc	rax
	mov	QWORD PTR i$3[rsp], rax
$LN4@main:
	cmp	QWORD PTR i$3[rsp], 10000000		; 00989680H
	jae	SHORT $LN3@main

; 9    :     {
; 10   :         test();

	call	?test@@YAMXZ				; test

; 11   :     }

	jmp	SHORT $LN2@main
$LN3@main:

; 12   :  
; 13   :     for (size_t i = 0; i < 10000000; i++)

	mov	QWORD PTR i$4[rsp], 0
	jmp	SHORT $LN7@main
$LN5@main:
	mov	rax, QWORD PTR i$4[rsp]
	inc	rax
	mov	QWORD PTR i$4[rsp], rax
$LN7@main:
	cmp	QWORD PTR i$4[rsp], 10000000		; 00989680H
	jae	SHORT $LN6@main

; 14   :     {
; 15   :         auto f = []()->float {return 333 * 2.43; };

	lea	rax, QWORD PTR $T1[rsp]
	mov	rdi, rax
	xor	eax, eax
	mov	ecx, 1
	rep stosb

; 16   :         f();

	lea	rcx, QWORD PTR f$2[rsp]
	call	??R<lambda_a063bd16e7642c22fd3d9fd00722fd02>@@QEBAMXZ ; <lambda_a063bd16e7642c22fd3d9fd00722fd02>::operator()

; 17   :     }

	jmp	SHORT $LN5@main
$LN6@main:

; 18   :     return 0;

	xor	eax, eax

; 19   : }

	add	rsp, 64					; 00000040H
	pop	rdi
	ret	0
main	ENDP
_TEXT	ENDS
; Function compile flags: /Odtp
_TEXT	SEGMENT
?test@@YAMXZ PROC					; test

; 4    :     return 333 * 2.43;

	movss	xmm0, DWORD PTR __real@444a4c29

; 5    : }

	ret	0
?test@@YAMXZ ENDP					; test
_TEXT	ENDS
END
上个没优化的
jian_vv 2015-11-03
  • 打赏
  • 举报
回复
引用 1 楼 dustpg 的回复:
我以前也以为c++11的lambda就是一个函数指针, 所以存在效率问题. 然后发现实际是个functor, 效率是绝对的.
你的意思是编译期,就把这个函数编译好了?
fefe82 2015-11-03
  • 打赏
  • 举报
回复
引用 6 楼 jian_vv 的回复:
[quote=引用 5 楼 fefe82 的回复:]

$ cat test.cpp
#include <cstdlib>
float test()
{
    return 333 * 2.43;
}
int main(int, const char **)
{
    for (size_t i = 0; i < 10000000; i++)
    {
        test();
    }

    for (size_t i = 0; i < 10000000; i++)
    {
        auto f = []()->float {return 333 * 2.43; };
        f();
    }
    return 0;
}

$ g++ --std=c++11 --pedantic -g -O2 test.cpp
$ g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ objdump -d a.out > a.ss
a.ss

0000000000400400 <main>:
  400400:   31 c0                   xor    %eax,%eax
  400402:   c3                      retq
优化之后 main 只剩了一句 return 0;
我去。。。怎样才能测试得到真实的结果呢,但是我跑的时候确实经过几百毫秒啊[/quote] 那估计你没有开优化。 不过测效率不开优化没有什么意义。 ================== int test() { return rand(); } int n = 0; for (size_t i = 0; i < 10000000; i++) { n ^= test(); } printf ("%d\n", n); 这个应该不会被优化掉,不过两个地方应该都会被直接内联,不会有任何区别。
jian_vv 2015-11-03
  • 打赏
  • 举报
回复
引用 5 楼 fefe82 的回复:

$ cat test.cpp
#include <cstdlib>
float test()
{
    return 333 * 2.43;
}
int main(int, const char **)
{
    for (size_t i = 0; i < 10000000; i++)
    {
        test();
    }

    for (size_t i = 0; i < 10000000; i++)
    {
        auto f = []()->float {return 333 * 2.43; };
        f();
    }
    return 0;
}

$ g++ --std=c++11 --pedantic -g -O2 test.cpp
$ g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ objdump -d a.out > a.ss
a.ss

0000000000400400 <main>:
  400400:   31 c0                   xor    %eax,%eax
  400402:   c3                      retq
优化之后 main 只剩了一句 return 0;
我去。。。怎样才能测试得到真实的结果呢,但是我跑的时候确实经过几百毫秒啊
fefe82 2015-11-03
  • 打赏
  • 举报
回复

$ cat test.cpp
#include <cstdlib>
float test()
{
    return 333 * 2.43;
}
int main(int, const char **)
{
    for (size_t i = 0; i < 10000000; i++)
    {
        test();
    }

    for (size_t i = 0; i < 10000000; i++)
    {
        auto f = []()->float {return 333 * 2.43; };
        f();
    }
    return 0;
}

$ g++ --std=c++11 --pedantic -g -O2 test.cpp
$ g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ objdump -d a.out > a.ss
a.ss

0000000000400400 <main>:
  400400:   31 c0                   xor    %eax,%eax
  400402:   c3                      retq
优化之后 main 只剩了一句 return 0;
fefe82 2015-11-03
  • 打赏
  • 举报
回复
开了优化的话你写的所有这些代码可能都直接被编译器砍掉。 除了延迟了一些时间之外啥也没干。
ri_aje 2015-11-03
  • 打赏
  • 举报
回复
这么简单的情况,肯定优化了,看看汇编就知道了。

64,646

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧