哪个更快?++,+ =或x + 1?

App*_*ker 20 .net c# performance operators

我正在使用C#(这个问题也适用于像C++这样的类似语言),我试图找出最快,最有效的增量方法.在我的游戏中,它不仅仅是一个或两个增量,而是每秒300个增量.就像屏幕上每个精灵的帧都在递增,我的RPG角色的速度和位置,相机的偏移等等.所以我在想,最有效的方法是什么?例如,y_pos我可以做的每次运动增加5 :

1.

Player.YPos += 5;
Run Code Online (Sandbox Code Playgroud)

2.

Player.YPos = Player.YPos + 5;
Run Code Online (Sandbox Code Playgroud)

3.

for (int i = 0; i < 5; i++)
{
    Player.YPos++;
}
Run Code Online (Sandbox Code Playgroud)

哪个是最有效的(也是最快的)?

Jon*_*eet 90

(特定于C#作为C++的答案可能会有很大差异.)

1和2是等价的.

3肯定会慢一些.

话虽如此,每秒只做300次,你不会注意到任何差异.您是否知道计算机在一秒钟内可以在原始CPU +内存方面做多少?一般而言,您应该将代码编写为清晰度,这是最重要的事情.无论如何都要担心性能 - 但只有当你有办法测量它时,才能a)告诉你是否需要担心,以及b)是否有任何改变实际上改善了性能.

在这种情况下,我会说选项1是最清晰的,所以这就是我使用的.

  • @Frédéric嗯,你知道些什么.这些天你似乎不得不竭尽全力编写运行缓慢的代码! (18认同)
  • @Jon,@ David,我尝试使用g ++ 4.4.5循环:从`-O2`开始,优化器发出一个`addl $ 5,%eax`指令.我想优化是免费的,更重要的是:) (17认同)
  • 但是智能编译器可以检测到副作用的缺乏,展开循环然后将五个增量操作优化为单个添加,对吧?:) (12认同)
  • @Frédéric一个聪明的编译器可能确实认识到了这一点,但我希望编写我的编译器的人会花费他们的努力进行有用的优化. (8认同)
  • @burningprodigy:我希望"加5"可能需要几个周期而不是"增加1".但是当有疑问时,*测试*. (2认同)
  • @Frédéric:假设 C# 而不是 C++,C# 编译器不能这样做……JIT 编译器*可能*能够,但我怀疑它会。为什么要花时间寻找这样的优化,当开发人员应该只使用一个“+= 5”开始时? (2认同)
  • @burning这是高级语言的一个特征.编译后的代码没有运算符.这是运行的编译代码.你会发现,你可以检查,`i ++`,`i + = 1`和`i = i + 1`被编译成相同的代码. (2认同)

Dav*_*nan 31

选项1和2将导致编译器生成相同的代码.选项3将慢得多.

这是一个i++i += 1甚至更快的谬误i = i + 1.所有体面的编译器都会将这三个指令转换为相同的代码.

对于像添加这样的简单操作,编写最清晰的代码并让编译器担心使其快速.

  • @Beriel为什么会这样?编译器将为1和2发出相同的代码. (2认同)
  • 实际上,`++ i`比`i ++'快,但只有当`i`是一个对象时,甚至仅在某些情况下. (2认同)

Jac*_*lly 21

编译器应该为1和2生成相同的程序集,它可以在选项3中展开循环.当遇到这样的问题时,您可以使用一个有用的工具来实际测试正在发生的事情是查看编译器生成的程序集.在g ++中,这可以使用-S开关实现.

例如,选项1和2在使用命令编译时生成此汇编程序g++ -S inc.cpp(使用g ++ 4.5.2)


main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    addl    $5, -4(%rbp)
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

对于选项3,g ++产生效率明显较低的汇编程序:


main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    $0, -8(%rbp)
    jmp .L2
.L3:
    addl    $1, -4(%rbp)
    addl    $1, -8(%rbp)
.L2:
    cmpl    $4, -8(%rbp)
    setle   %al
    testb   %al, %al
    jne .L3
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

但是通过优化(偶数-O1),g ++可以为所有3个选项生成:


main:
.LFB0:
    .cfi_startproc
    leal    5(%rdi), %eax
    ret
    .cfi_endproc
Run Code Online (Sandbox Code Playgroud)

g ++不仅可以在选项3中展开循环,而且还使用lea指令在单个指令中进行添加,而不是使用mov.

因此,g ++将始终为选项1和2生成相同的程序集.只有在明确打开优化(这是您可能期望的行为)时,g ++才会为所有3个选项生成相同的程序集.

(看起来你应该能够检查由C#生成的程序集,虽然我从来没有尝试过)

  • @NitinJS OP确实说"这个问题对C++这样的类似语言也有效",它标记了C++和C#. (6认同)