Why is i=i+1 faster than i++?

后端 未结 5 628
野性不改
野性不改 2021-01-13 09:04

Test this code in Flash:

var i:int = 0;
for (var j:int = 0; j < 5000000; j++)
{
    i=i+1;
}// use about 300ms.

i = 0;
for (var j:int = 0; j < 5000000         


        
相关标签:
5条回答
  • 2021-01-13 09:23

    I don't have a response to your question but the following has been the fastest among all the loops I tried.

    import flash.utils.getTimer;
    
    var t:int = getTimer();
    var i:int = 0, j:int = -1;
    while (++j < 5000000) {
        i += 1;
    }
    trace(getTimer()-t)
    

    This gives me 83 ms.

    0 讨论(0)
  • 2021-01-13 09:26

    I suggest instead of i++; use ++i; Because it is faster than both you mentioned.

    Look at this good explanation: What is more efficient i++ or ++i?

    0 讨论(0)
  • 2021-01-13 09:27

    ++ and -- operators were designed to resemble the assembly code for increment and decrement, but nowadays it shouldn't make much difference with advancement of compilers. See section increase and decrease

    It could be a change in implementation or a temporary regression in actionscript virtual machine.

    0 讨论(0)
  • 2021-01-13 09:32

    I can't replicate this behavior all three appear to be about the same time for me

    Attempt 1
    loop 1: 378
    loop 2: 396
    loop 3: 382
    
    Attempt 2
    loop 1: 380
    loop 2: 361
    loop 3: 361
    
    Attempt 3
    loop 1: 375
    loop 2: 373
    loop 3: 355
    

    Increasing the loops by a factor of 10 I got these times:

    Attempt 1
    loop 1: 3707
    loop 2: 3663
    loop 3: 3653
    
    Attempt 2
    loop 1: 3722
    loop 2: 3632
    loop 3: 3711
    

    [TestLoopSpeed.as]

    package
    {
        import flash.display.Sprite;
        import flash.utils.getTimer;
    
        public class TestLoopSpeed extends Sprite
        {
            public function TestLoopSpeed()
            {
                var timeNow:Number = getTimer();
                var i:int = 0;
    
                var startOne:Number = getTimer();
                for (var j:int = 0; j < 5000000; j++)
                {
                    i=i+1;
                }
                var endOne:Number = getTimer();
    
    
                var startTwo:Number = getTimer();
                i = 0;
                for (var j:int = 0; j < 5000000; j++)
                {
                    i++;
                }
                var endTwo:Number = getTimer();
    
                var startThree:Number = getTimer();
                i = 0;
                for (var j:int = 0; j < 5000000; j++)
                {
                    ++i;
                }
                var endThree:Number = getTimer();
    
                trace("loop 1: " + (endOne - startOne));
                trace("loop 2: " + (endTwo - startTwo));
                trace("loop 3: " + (endThree - startThree));
            }
        }
    }
    

    So far as I understand it i++ is ultimately equivalent to i = i+1; with the exception that if an assignment is occurring on that line then the current value of i would be used and a later instruction would add one to i. ++i simply means add 1 to i before doing any other operations on this line. Ultimately I don't think any of these options should really affect performance it appears from every test I've done that the CPU scheduling at any given moment for the flash process is having more of an effect than any given operator.

    If there's something wrong with the code I'm using to test please point it out.

    Edit

    Updated the code to include the while loop option, still not seeing anything that looks like a positive significant difference:

    loop 1: 3695
    loop 2: 3698
    loop 3: 3690
    loop 4: 3711
    
    loop 1: 3758
    loop 2: 3651
    loop 3: 3707
    loop 4: 3676
    

    [TestLoopSpeed.as] Updated with fancy while loop pre-increment action

    package
    {
        import flash.display.Sprite;
        import flash.utils.getTimer;
    
        public class TestLoopSpeed extends Sprite
        {
            public function TestLoopSpeed()
            {
                var timeNow:Number = getTimer();
                var i:int = 0;
    
                var startOne:Number = getTimer();
                for (var j:int = 0; j < 50000000; j++)
                {
                    i=i+1;
                }
                var endOne:Number = getTimer();
    
    
                var startTwo:Number = getTimer();
                i = 0;
                for (var j:int = 0; j < 50000000; j++)
                {
                    i++;
                }
                var endTwo:Number = getTimer();
    
                var startThree:Number = getTimer();
                i = 0;
                for (var j:int = 0; j < 50000000; j++)
                {
                    ++i;
                }
                var endThree:Number = getTimer();
    
                var startFour:Number = getTimer();
                i = 0;
                var j:int = -1;
                while (++j < 50000000)
                {
                    ++i;
                }
                var endFour:Number = getTimer();
    
                trace("loop 1: " + (endOne - startOne));
                trace("loop 2: " + (endTwo - startTwo));
                trace("loop 3: " + (endThree - startThree));
                trace("loop 4: " + (endFour - startFour));
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-13 09:44

    Where your loop is situated can have a large impact on performance. If your loop is inside a function, Flash will perform calculations using local registers. The loop containing i++ produces thus the following opcodes:

    000013 inclocal_i (REG_2)  ; increment i 
    000015 inclocal_i (REG_3)  ; increment j
    000017 getlocal (REG_3)    ; push j onto stack
    000018 pushint 5000000     ; push 5000000 onto stack
    000020 iflt -12            ; jump backward if less than
    

    The loop containing i = i + 1 produces the following:

    000013 getlocal (REG_2)    ; push i onto stack
    000014 pushbyte 1          ; push 1 onto stack
    000016 add                 ; add the two
    000017 convert_i           ; coerce to integer
    000018 setlocal (REG_2)    ; save i back to register 2
    000019 inclocal_i (REG_3)  
    000021 getlocal (REG_3)
    000022 pushint 5000000
    000024 iflt -16
    

    i++ is faster than i = i + 1 here since inclocal_i modifies the register directly, without having to load the register onto the stack and saving it back.

    The loop becomes be far less efficient when you put it inside a frame script. Flash will store declared variables as class variables. Accessing those requires more work. The i++ loop results in the following:

    000017 getlocal (REG_0, this)   ; push this onto stack
    000018 dup                      ; duplicate it
    000019 setlocal (REG_2)         ; save this to register 2
    000020 getproperty i            ; get property "i"
    000022 increment_i              ; add one to it
    000023 setlocal (REG_3)         ; save result to register 3
    000024 getlocal (REG_2)         ; get this from register 2
    000025 getlocal (REG_3)         ; get value from register 3
    000026 setproperty i            ; set property "i"
    000028 kill (REG_3)             ; kill register 2
    000030 kill (REG_2)             ; kill register 3
    000032 getlocal (REG_0, this)   ; do the same thing with j...
    000033 dup
    000034 setlocal (REG_2)
    000035 getproperty j
    000037 increment_i
    000038 setlocal (REG_3)
    000039 getlocal (REG_2)
    000040 getlocal (REG_3)
    000041 setproperty j
    000043 kill (REG_3)
    000045 kill (REG_2)
    000047 getlocal (REG_0, this)
    000048 getproperty j
    000050 pushint 5000000
    000052 iflt -40
    

    The i = i + 1 version is somewhat shorter:

    000017 getlocal (REG_0, this)   ; push this onto stack
    000018 getlocal (REG_0, this)   ; push this onto stack
    000019 getproperty i            ; get property "i"
    000021 pushbyte 1               ; push 1 onto stack
    000023 add                      ; add the two
    000024 initproperty i           ; save result to property "i"
    000026 getlocal (REG_0, this)   ; increment j...
    000027 dup
    000028 setlocal (REG_2)
    000029 getproperty j
    000031 increment_i
    000032 setlocal (REG_3)
    000033 getlocal (REG_2)
    000034 getlocal (REG_3)
    000035 setproperty j
    000037 kill (REG_3)
    000039 kill (REG_2)
    000041 getlocal (REG_0, this)
    000042 getproperty j
    000044 pushint 5000000
    000046 iflt -34 
    
    0 讨论(0)
提交回复
热议问题