x = x + 1对x + = 1

时间:2009-04-30 17:15:39

标签: vb.net performance operators

我的印象是这两个命令导致相同的结果,即将X递增1,但后者可能更有效。

如果这不正确,请解释差异。

如果它是正确的,为什么后者会更有效率?他们不应该编译到同一个IL吗?

感谢。

17 个答案:

答案 0 :(得分:106)

来自MSDN library for +=

  

使用此运算符与指定result = result + expression几乎相同,只是结果只计算一次。

所以它们不相同,这就是x + = 1效率更高的原因。

更新:我刚刚注意到我的MSDN Library链接是JScript页面而不是VB page,它不包含相同的引用。

因此,经过进一步的研究和测试,该答案不适用于VB.NET。我错了。这是一个示例控制台应用程序:

Module Module1

Sub Main()
    Dim x = 0
    Console.WriteLine(PlusEqual1(x))
    Console.WriteLine(Add1(x))
    Console.WriteLine(PlusEqual2(x))
    Console.WriteLine(Add2(x))
    Console.ReadLine()
End Sub

Public Function PlusEqual1(ByVal x As Integer) As Integer
    x += 1
    Return x
End Function

Public Function Add1(ByVal x As Integer) As Integer
    x = x + 1
    Return x
End Function

Public Function PlusEqual2(ByVal x As Integer) As Integer
    x += 2
    Return x
End Function

Public Function Add2(ByVal x As Integer) As Integer
    x = x + 2
    Return x
End Function

End Module

PlusEqual1和Add1的IL确实相同:

.method public static int32 Add1(int32 x) cil managed
{
.maxstack 2
.locals init (
    [0] int32 Add1)
L_0000: nop 
L_0001: ldarg.0 
L_0002: ldc.i4.1 
L_0003: add.ovf 
L_0004: starg.s x
L_0006: ldarg.0 
L_0007: stloc.0 
L_0008: br.s L_000a
L_000a: ldloc.0 
L_000b: ret 
}

IL for PlusEqual2和Add2几乎完全相同:

.method public static int32 Add2(int32 x) cil managed
{ 
.maxstack 2
.locals init (
    [0] int32 Add2)
L_0000: nop 
L_0001: ldarg.0 
L_0002: ldc.i4.2 
L_0003: add.ovf 
L_0004: starg.s x
L_0006: ldarg.0 
L_0007: stloc.0 
L_0008: br.s L_000a
L_000a: ldloc.0 
L_000b: ret 
}

答案 1 :(得分:25)

我写了一个简单的控制台应用程序:

static void Main(string[] args)
{
    int i = 0;
    i += 1;
    i = i + 1;
    Console.WriteLine(i);
}

我使用Reflector对它进行了反汇编,这就是我得到的:

private static void Main(string[] args)
{
    int i = 0;
    i++;
    i++;
    Console.WriteLine(i);
}

他们是一样的。

答案 2 :(得分:18)

他们编译成相同的,第二个更容易输入。

答案 3 :(得分:11)

重要:

在一般语言中,指定评估的答案在+=所做的事情方面肯定是正确的。但是在VB.NET中,我假设OP中指定的X是变量或属性。


他们可能会编译到同一个IL。

更新(解决可能存在的争议):

VB.NET是一种编程语言的规范。任何符合规范中定义的编译器都可以是VB.NET实现。如果您编辑MS VB.NET编译器的源代码以生成X += 1案例的糟糕代码,您仍将符合VB.NET规范(因为它没有说明它将如何工作。它只是说效果将完全相同,这使得生成相同的代码确实合乎逻辑。

虽然编译器很可能(我觉得它确实如此)为两者生成相同的代码,但它是相当复杂的软件。哎呀,你甚至不能保证编译器在编译两次相同的代码时生成完全相同的代码!

你可以100%安全地说(除非你知道编译器的源代码)是一个好的编译器应该生成相同的代码,性能方面,这可能或可能不是完全相同的代码

答案 4 :(得分:8)

这么多猜测!即使是使用Reflector thingy的结论也不一定正确,因为它可以在反汇编时进行优化。

那么为什么你们这些人都没看过IL代码?看看下面的C#程序:

static void Main(string[] args)
{
    int x = 2;
    int y = 3;
    x += 1;
    y = y + 1;
    Console.WriteLine(x);
    Console.WriteLine(y);
}

此代码段编译为:

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 x,
[1] int32 y)
// some commands omitted here

IL_0004: ldloc.0
IL_0005: ldc.i4.1
IL_0006: add
IL_0007: stloc.0

IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stloc.1

// some commands omitted here
}

正如您所看到的,它实际上完全相同。为什么呢?因为IL的目的是告诉做什么,而不是如何做。优化将是JIT编译器的工作。顺便说一句,它在VB.Net中是一样的

答案 5 :(得分:4)

在x86上,如果x在寄存器eax中,它们都会产生类似

的内容

inc eax;

所以你是对的,在一些编译阶段之后,IL将是相同的。

这类问题可以用“信任你​​的优化者”来回答。

着名的神话是 X ++;
效率低于
++ X;
因为它必须存储一个临时值。如果您从不使用临时值,优化程序将删除该存储。

答案 6 :(得分:2)

是一样的。

x=x+1 

是数学上的矛盾,而

x+=1

不是,而且打字很轻。

答案 7 :(得分:2)

如果x是一个简单的类型,如int或float。

,优化器可能会产生相同的结果

如果你使用其他语言(这里有限的VB知识,你可以重载+ =?),其中x可能是一个大的鸣笛对象,前者创建和额外的副本,可以是数百兆。后者没有。

答案 8 :(得分:2)

  1. 是的,他们的行为相同。
  2. 不,他们可能同样有效率。优化器在这方面很擅长。如果您想要仔细检查,请编写优化代码并在反射器中查看。

答案 9 :(得分:2)

它们在VB中可能是相同的;它们在C中并不一定相同(操作员来自)。

答案 10 :(得分:1)

在C ++中,它取决于 x 的数据类型以及如何定义运算符。如果 x 是某个类的实例,则可以获得完全不同的结果。

或许您应该解决问题并指定 x 是整数或其他。

答案 11 :(得分:1)

我认为差异是由于用于内存引用的额外时钟周期,但我结果证明是错误的!我自己无法理解这件事

instruction type        example                      cycles

=============================================== ====================

ADD reg,reg             add ax,bx                       1
ADD mem,reg             add total, cx                   3
ADD reg,mem             add cx,incr                     2
ADD reg,immed           add bx,6                        1
ADD mem,immed           add pointers[bx][si],6          3
ADD accum,immed         add ax,10                       1

INC reg                 inc bx                          1
INC mem                 inc vpage                       3

MOV reg,reg             mov bp,sp                       1
MOV mem,reg             mov array[di],bx                1
MOV reg,mem             mov bx,pointer                  1
MOV mem,immed           mov [bx],15                     1
MOV reg,immed           mov cx,256                      1
MOV mem,accum           mov total,ax                    1
MOV accum,mem           mov al,string                   1
MOV segreg,reg16        mov ds,ax                       2, 3
MOV segreg,mem16        mov es,psp                      2, 3
MOV reg16,segreg        mov ax,ds                       1
MOV mem16,segreg        mov stack_save,ss               1
MOV reg32,controlreg    mov eax,cr0                     22
                        mov eax,cr2                     12
                        mov eax,cr3                     21, 46
                        mov eax,cr4                     14
MOV controlreg,reg32    mov cr0,eax                     4
MOV reg32,debugreg      mov edx,dr0                     DR0-DR3,DR6,DR7=11;
                                                        DR4,DR5=12 
MOV debugreg,reg32      mov dr0,ecx                     DR0-DR3,DR6,DR7=11;
                                                        DR4,DR5=12 

源:http://turkish_rational.tripod.com/trdos/pentium.txt

指令可以翻译为:

;for i = i+1   ; cycles
mov  ax,   [i]  ; 1
add  ax,   1    ; 1
mov  [i],  ax   ; 1

;for i += 1
; dunno the syntax of instruction. it should be the pointers one :S     

;for i++
inc  i          ; 3
;or
mov  ax,   [i]  ; 1
inc  ax         ; 1
mov  [i],  ax   ; 1

;for ++i
mov  ax,   [i]  ; 1
;do  stuff      ; matters not
inc  ax         ; 1
mov  [i],  ax   ; 1
结果都是一样的:S 它只是一些可能有用的数据。请评论!

答案 12 :(得分:1)

值得注意的是+ =, - =,* =等进行隐式演员。

int i = 0;
i = i + 5.5; // doesn't compile.
i += 5.5; // compiles.

答案 13 :(得分:0)

程序效率没有区别;只是输入效率。

答案 14 :(得分:0)

早在20世纪80年代初,莱迪思C编译器的一个非常酷的优化是“x = x + 1;”,“x + = 1;”和“x ++;”所有产生完全相同的机器代码。如果他们能够做到这一点,那么千禧年编写的编译器肯定能够做到。

答案 15 :(得分:0)

在运行时(至少使用PERL)没有区别。 x + = 1大约比x = x + 1快0.5秒,但是

答案 16 :(得分:0)

如果x是一个简单的整数标量变量,它们应该是相同的。

如果x是一个大表达式,可能带有副作用,+=1++应该快两倍。

许多人专注于这种低级优化,就好像这就是优化的全部内容。我猜你知道这是一个更大的主题。