2016-05-31 3 views
3

아래의 두 접근 자 함수 사이의 속도 차이를 측정 한 테스트를 실행했으며 예상 시간의 차이가 예상보다 컸습니다. 나는 속기 구현이 좀 더 빠를 것이라는 느낌을 받았기 때문에 그것을 시험하고 싶었다.속기 접근 자 기능이 일반 카운터보다 빠릅니다.

각 클래스에 대해 Get 함수를 호출하기 위해 필요한 총 총 시간 (초)을 10 억 회 반복했습니다.

using System; 
using System.Diagnostics; 

class SimpleGet { 
    int value; 

    public int Get() { 
     return value; 
    } 
} 

class ShorthandGet { 
    int value; 

    public int Get() => value; 
} 

class Program { 
    static void Main() { 
     const int Iterations = 1000000000; 
     Stopwatch sw = new Stopwatch(); 

     sw.Start(); 
     { 
      int n; SimpleGet sg = new SimpleGet(); 
      for (int i = 0; i < Iterations; i++) { 
       n = sg.Get(); 
      } 
     } 
     sw.Stop(); 
     Console.WriteLine("SimpleGet: " + sw.Elapsed.TotalSeconds); 

     sw.Reset(); 

     sw.Start(); 
     { 
      int n; ShorthandGet shg = new ShorthandGet(); 
      for (int i = 0; i < Iterations; i++) { 
       n = shg.Get(); 
      } 
     } 
     sw.Stop(); 
     Console.WriteLine("ShorthandGet: " + sw.Elapsed.TotalSeconds); 

     Console.ReadLine(); 

    } 
} 

결과 :

// 1 billion iterations 
SimpleGet: 11.8484244 
ShorthandGet: 4.3218568 

속도의 차이가 크다. 내가 볼 수있는 유일한 차이점은 일반 함수에는 대괄호가 있고 따라서 함수 호출에 새로운 범위가 작성된다는 것입니다. 범위 안에 새로운 변수가 없기 때문에 이론적으로 "무시"해서는 안되는가? 누군가 정규 함수가 다른 함수와 동일한 수준으로 최적화되지 않은 이유를 설명 할 수 있습니까?

편집 나는 특성을 가진 동일한 시나리오를 테스트 : Value { get { return value; } }Value => value;와의 시간 차이를 우리는 각각의 기능을 시간의 차이에 매우 가까이있어. 나는 그 원인이 같다고 생각한다.

+0

디버거를 연결하지 않고 최적화 된 빌드 (즉, 출시하지 않음 디버그)에서이 벤치 마크를 실행 했습니까? –

+0

예, 디버그 모드에있을 때와 동일한 결과가 표시됩니다. 그러나 Release로 변경하면 두 루프가 약 2.3 초가됩니다. – Jonesopolis

+0

네 말이 맞아, 그건 내 부분에서 무지이었다. 내가 릴리스 디버거없이 빌드를 시도, 그들은 거의 같았습니다. – Dave

답변

8

간단히 대답하면 제대로 완료된 벤치 마크에는 차이가 없다는 것입니다.

이러한 최적화 최적화 사례의 경우 IL에서 먼저 들으려고합니다. 깊은 통찰력을 얻을 수 있기 때문에가 아니라 동일한 IL이 생성되면 런타임에 차이가 없어야하기 때문입니다. 다음으로 기억해야 할 것은 컴파일러가 해당 빌드에서 불필요한 IL 명령어를 제거하기 때문에 릴리스 빌드에서 시작해야한다는 것입니다. 에서 그러나

.method public hidebysig 
    instance int32 Get() cil managed 
{ 
    IL_0000: ldarg.0 
    IL_0001: ldfld int32 ConsoleApplication7.ShorthandGet::'value' 
    IL_0006: ret 
} 

최적화 다음 ShorthandGet 훨씬 짧은 대

.method public hidebysig 
    instance int32 Get() cil managed 
{ 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: ldfld int32 ConsoleApplication7.SimpleGet::'value' 
    IL_0007: stloc.0 
    IL_0008: br.s IL_000a 
    IL_000a: ldloc.0 
    IL_000b: ret 
} 

: 디버그 빌드에서

는 긴 형식 IL (SimpleGet)는 브레이크 포인트를 배치 할 수 있도록 추가 지침을 가지고 빌드, 두 양식은 위의 ShorthandGet과 동일한 IL을 만듭니다.

디버그 빌드의 벤치 마크는 시연 한 것처럼 차이점을 표시 할 수 있지만, 성능에 신경 쓰면 릴리스 빌드의 최적화 된 코드를 실행하므로 비교할 가치가 없습니다. 이야기의 도덕은 최적화 된 코드에 대한 실적 분석을 항상 수행하는 것입니다. 누락 된 추가 항목은 최적화 된 IL을 위해조차도 디버거가 연결되지 않은 채 벤치 마크하는 것입니다. JIT는 디버거를 감지하고 더 많은 디버깅 가능한 머신 코드를 방출합니다. VS에서 "시작"을 누르거나 F5를 누르기 때문에 많은 사람들이 놓친다. 그러나이 은 디버거가으로 시작되면서 프로그램을 시작한다. 디버그> 디버깅하지 않고 시작 메뉴 옵션을 사용하십시오.