2012-08-31 41 views
5

thử mã này trong Flash:Tại sao i = i + 1 nhanh hơn i + +?

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; j++) 
{ 
    i++; 
}// use about 400ms 

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

Tại sao i=i+1 nhanh hơn trong ActionScript 3 khi nó chậm hơn những người khác?

Xin lỗi, tôi thực hiện một số lỗi. Mã ở trên sử dụng cùng một lúc. nhưng nếu đặt vào chức năng và kết quả sẽ khác.

var i:int; 
var j:int; 
var startTime:Number; 

function func1():void 
{ 
    i = i + 1; 
} 

function func2():void 
{ 
    i++; 
} 

startTime = getTimer(); 
i = 0; 
for (j = 0; j < 10000000; j++) 
{ 
    func1(); 
} 
trace(getTimer() - startTime);//5 times:631,628,641,628,632 

startTime = getTimer(); 
i = 0; 
for (j = 0; j < 10000000; j++) 
{ 
    func2(); 
} 
trace(getTimer() - startTime);//5 times:800,814,791,832,777 
+3

bạn Can lần 10 chiều dài vòng lặp, và chắc chắn rằng đó thực sự là một sự khác biệt? – scientiaesthete

+0

Bạn có ý nghĩa gì bởi "chậm hơn ở những người khác?" Các ngôn ngữ lập trình khác? Cái nào? –

+0

Lưu ý nhỏ: Việc bạn có cài đặt release-/debugbuild ('cho phép gỡ lỗi' trong FlashIDE) có quan trọng không, và kết quả cũng có thể thay đổi trong bản phát hành và trình gỡ lỗi. http://jacksondunstan.com có ​​rất nhiều bài kiểm tra hiệu suất chuyên sâu cho một số người chơi. –

Trả lời

5

đâu vòng lặp của bạn nằm có thể có một ảnh hưởng lớn tới hiệu suất. Nếu vòng lặp của bạn nằm bên trong một hàm, Flash sẽ thực hiện các phép tính bằng cách sử dụng thanh ghi cục bộ. Vòng lặp chứa i++ sản xuất do đó opcodes sau:

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 

vòng lặp chứa i = i + 1 sản xuất như sau:

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++ nhanh hơn i = i + 1 đây từ inclocal_i đổi sổ đăng ký trực tiếp, mà không cần phải nạp đăng ký vào ngăn xếp và lưu lại.

Vòng lặp trở nên kém hiệu quả hơn khi bạn đặt nó bên trong tập lệnh khung. Flash sẽ lưu các biến được khai báo dưới dạng các biến lớp. Việc truy cập những thứ đó đòi hỏi nhiều công việc hơn. Các i++ kết quả vòng trong sau:

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 

Phiên bản i = i + 1 là hơi ngắn hơn:

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

Tôi thích câu trả lời của bạn tốt hơn rất nhiều so với tôi :) làm thế nào để bạn có được opcodes bạn vừa sửa đổi mm.cfg bằng cách nào đó? – shaunhusain

+1

Tôi đã viết một bộ tách AS3. Bạn có thể kiểm tra tại: http://flaczki.net46.net/codedump/. Có thể khó để tối ưu hóa hiệu suất. – cleong

+0

Cảm ơn bạn thật tuyệt vời! Tôi đang chuyển một số sang HTML5/JS vì vậy tôi phải dựa vào các công cụ AS3 một chút nhưng tôi chắc chắn sẽ lưu trữ để kiểm tra đôi khi sớm. – shaunhusain

4

tôi không thể tái tạo hành vi này cả ba xuất hiện vào khoảng cùng thời gian cho tôi

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 

Tăng vòng bởi một yếu tố của 10 Tôi có những thời điểm:

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)); 
     } 
    } 
} 

Cho đến nay, tôi hiểu nó i ++ là cuối cùng tương đương với i = i + 1; với ngoại lệ là nếu một phép gán xảy ra trên dòng đó thì giá trị hiện tại của tôi sẽ được sử dụng và lệnh sau sẽ thêm một cho tôi. ++ tôi chỉ đơn giản là thêm 1 cho tôi trước khi thực hiện bất kỳ thao tác nào khác trên dòng này. Cuối cùng tôi không nghĩ rằng bất kỳ tùy chọn nào thực sự ảnh hưởng đến hiệu suất, nó xuất hiện từ mọi thử nghiệm mà tôi đã thực hiện là lập lịch CPU tại bất kỳ thời điểm nào cho quá trình flash có nhiều hiệu ứng hơn bất kỳ toán tử nào.

Nếu có điều gì đó sai với mã tôi đang sử dụng để kiểm tra, vui lòng chỉ ra.

Sửa

Cập nhật mã để bao gồm các vòng lựa chọn thời gian, vẫn không thấy bất cứ điều gì đó trông giống như một sự khác biệt đáng kể tích cực:

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] cập nhật với thời gian ưa thích hành động tăng trước vòng lặp

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

Tôi không có một câu trả lời cho câu hỏi của bạn nhưng sau đây là nhanh nhất trong số tất cả các vòng tôi đã thử.

import flash.utils.getTimer; 

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

Điều này mang lại cho tôi 83 mili giây.

2

++ và - toán tử được thiết kế giống với mã lắp ráp để tăng và giảm, nhưng ngày nay nó không tạo nên sự khác biệt nhiều với tiến trình biên dịch. See section increase and decrease

Nó có thể là thay đổi trong triển khai hoặc tạm thời regression trong máy ảo ActionScript.

0

Tôi đề nghị thay vì i++; sử dụng ++i; Vì nó nhanh hơn cả bạn đã đề cập.

Xem giải thích tốt này: What is more efficient i++ or ++i?

+0

Điều đáng nói đến là biến sẽ không giữ nguyên giá trị sau mỗi thao tác đó có nghĩa là chúng không thể hoán đổi cho nhau mà không thay đổi mã sử dụng biến này. –

0

Cũng phụ thuộc vào tất cả ngôn ngữ. Maby trong AS3 $ i = $ i + 1 nhanh hơn, trong PHP $ i ++ là. Nhưng giống như Almas Adilbek nói. ++ $ i là nhanh nhất.

Ví dụ

<?php 
    $start = microtime(); 

    $i = 0; 
    while($i != 100000) 
    { 
     $i++; 
    } 

    $end = microtime(); 

    echo 'First complete in: ' . ($end - $start); 

    $start = microtime(); 

    $i = 0; 
    while($i != 100000) 
    { 
     $i = $i+1; 
    } 

    $end = microtime(); 

    echo 'Second complete in: ' . ($end - $start); 

    $start = microtime(); 

    $i = 0; 
    while($i != 100000) 
    { 
     ++$i; 
    } 

    $end = microtime(); 

    echo 'Third complete in: ' . ($end - $start); 
?> 
Các vấn đề liên quan