ProgramingTip

IF가 IF-ELSE보다 더 잘 검증 되었습니까?

bestdevel 2020. 11. 16. 21:56
반응형

IF가 IF-ELSE보다 더 잘 검증 되었습니까?


이 코드 블록 중 어느 것이 더 나은 성능을 수행하고 어느 것이 더 읽기 쉬운가요? 나는 특히 두 번째 블록에서 이득이 무시할 만하다고 생각합니다. 나는 단지 궁금하다.

블록 # 1

string height;
string width;
if (myFlag == 1)
{
    height = "60%";
    width = "60%";
}
else
{
    height = "80%";
    width = "80%";
}

블록 # 2

string height = "80%";
string width = "80%";
if (myFlag == 1)
{
    height = "60%";
    width = "60%";
}

업데이트 됨

위의 코드를 테스트했을 때 결과는 두 블록이 동일하게 수행 할 것입니다.

블록 # 1

myFlag = 1:   3 Milliseconds
myFlag = 0:   3 Milliseconds

블록 # 2

myFlag = 1:   3 Milliseconds
myFlag = 0:   3 Milliseconds

한 가지 중요한 점은 ( Matthew Steeples 답변 덕분에 여기에 있습니다 ) 테스트 한 코드 블록이 if-else 및 if 블록의 할당을 제외하고 변수 높이와 너비를 사용하지 않는 즉시 기 때문에 Code Block-1 및 2 에서 컴파일러는 문제의 if 및 if-else 블록을 완전히 제거하여 IL 코드를 최적화하여 여기에서 테스트에 대한 잘못된 결과를 표시합니다 .

코드 블록을 모두 업데이트하여 높이와 너비의 값을 파일에 기록하여 다시 사용하고 컴파일러가 테스트 블록을 실행하도록 강제했지만 (희망) 실제 파일 작성 부분이 코드에서 관찰 할 수 있습니다. 테스트 결과에 영향을주지 않습니다.

업데이트 된 결과, C # 및 IL 코드입니다.

결과

블록 # 1

myFlag = 1:   1688 Milliseconds
myFlag = 0:   1664 Milliseconds

블록 # 2

myFlag = 1:   1700 Milliseconds
myFlag = 0:   1677 Milliseconds

C # .net 코드

블록 # 1

    public long WithIfAndElse(int myFlag)
    {
        Stopwatch myTimer = new Stopwatch();
        string someString = "";
        myTimer.Start();
        for (int i = 0; i < 1000000; i++)
        {
            string height;
            string width;
            if (myFlag == 1)
            {
                height = "60%";
                width = "60%";
            }
            else
            {
                height = "80%";
                width = "80%";
            }
            someString = "Height: " + height + Environment.NewLine + "Width: " + width;
        }
        myTimer.Stop();
        File.WriteAllText("testifelse.txt", someString);
        return myTimer.ElapsedMilliseconds;
    }

블록 # 2

    public long WithOnlyIf(int myFlag)
    {
         Stopwatch myTimer = new Stopwatch();
        string someString = "";
        myTimer.Start();
        for (int i = 0; i < 1000000; i++)
        {
            string height = "80%";
            string width = "80%";
            if (myFlag == 1)
            {
                height = "60%";
                width = "60%";
            }
            someString = "Height: " + height + Environment.NewLine + "Width: " + width;
        }
        myTimer.Stop();
        File.WriteAllText("testif.txt", someString);
        return myTimer.ElapsedMilliseconds;
    }

ildasm.exe에 의해 생성 된 IL 코드

블록 # 1

.method public hidebysig instance int64  WithIfAndElse(int32 myFlag) cil managed
{
  // Code size       144 (0x90)
  .maxstack  3
  .locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
           [1] string someString,
           [2] int32 i,
           [3] string height,
           [4] string width,
           [5] string[] CS$0$0000)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldstr      ""
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_0070
  IL_0016:  ldarg.1
  IL_0017:  ldc.i4.1
  IL_0018:  bne.un.s   IL_0029
  IL_001a:  ldstr      "60%"
  IL_001f:  stloc.3
  IL_0020:  ldstr      "60%"
  IL_0025:  stloc.s    width
  IL_0027:  br.s       IL_0036
  IL_0029:  ldstr      "80%"
  IL_002e:  stloc.3
  IL_002f:  ldstr      "80%"
  IL_0034:  stloc.s    width
  IL_0036:  ldc.i4.5
  IL_0037:  newarr     [mscorlib]System.String
  IL_003c:  stloc.s    CS$0$0000
  IL_003e:  ldloc.s    CS$0$0000
  IL_0040:  ldc.i4.0
  IL_0041:  ldstr      "Height: "
  IL_0046:  stelem.ref
  IL_0047:  ldloc.s    CS$0$0000
  IL_0049:  ldc.i4.1
  IL_004a:  ldloc.3
  IL_004b:  stelem.ref
  IL_004c:  ldloc.s    CS$0$0000
  IL_004e:  ldc.i4.2
  IL_004f:  call       string [mscorlib]System.Environment::get_NewLine()
  IL_0054:  stelem.ref
  IL_0055:  ldloc.s    CS$0$0000
  IL_0057:  ldc.i4.3
  IL_0058:  ldstr      "Width: "
  IL_005d:  stelem.ref
  IL_005e:  ldloc.s    CS$0$0000
  IL_0060:  ldc.i4.4
  IL_0061:  ldloc.s    width
  IL_0063:  stelem.ref
  IL_0064:  ldloc.s    CS$0$0000
  IL_0066:  call       string [mscorlib]System.String::Concat(string[])
  IL_006b:  stloc.1
  IL_006c:  ldloc.2
  IL_006d:  ldc.i4.1
  IL_006e:  add
  IL_006f:  stloc.2
  IL_0070:  ldloc.2
  IL_0071:  ldc.i4     0xf4240
  IL_0076:  blt.s      IL_0016
  IL_0078:  ldloc.0
  IL_0079:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_007e:  ldstr      "testifelse.txt"
  IL_0083:  ldloc.1
  IL_0084:  call       void [mscorlib]System.IO.File::WriteAllText(string,
                                                                   string)
  IL_0089:  ldloc.0
  IL_008a:  callvirt   instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
  IL_008f:  ret
} // end of method frmResearch::WithIfAndElse

블록 # 2

.method public hidebysig instance int64  WithOnlyIf(int32 myFlag) cil managed
{
  // Code size       142 (0x8e)
  .maxstack  3
  .locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
           [1] string someString,
           [2] int32 i,
           [3] string height,
           [4] string width,
           [5] string[] CS$0$0000)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldstr      ""
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_006e
  IL_0016:  ldstr      "80%"
  IL_001b:  stloc.3
  IL_001c:  ldstr      "80%"
  IL_0021:  stloc.s    width
  IL_0023:  ldarg.1
  IL_0024:  ldc.i4.1
  IL_0025:  bne.un.s   IL_0034
  IL_0027:  ldstr      "60%"
  IL_002c:  stloc.3
  IL_002d:  ldstr      "60%"
  IL_0032:  stloc.s    width
  IL_0034:  ldc.i4.5
  IL_0035:  newarr     [mscorlib]System.String
  IL_003a:  stloc.s    CS$0$0000
  IL_003c:  ldloc.s    CS$0$0000
  IL_003e:  ldc.i4.0
  IL_003f:  ldstr      "Height: "
  IL_0044:  stelem.ref
  IL_0045:  ldloc.s    CS$0$0000
  IL_0047:  ldc.i4.1
  IL_0048:  ldloc.3
  IL_0049:  stelem.ref
  IL_004a:  ldloc.s    CS$0$0000
  IL_004c:  ldc.i4.2
  IL_004d:  call       string [mscorlib]System.Environment::get_NewLine()
  IL_0052:  stelem.ref
  IL_0053:  ldloc.s    CS$0$0000
  IL_0055:  ldc.i4.3
  IL_0056:  ldstr      "Width: "
  IL_005b:  stelem.ref
  IL_005c:  ldloc.s    CS$0$0000
  IL_005e:  ldc.i4.4
  IL_005f:  ldloc.s    width
  IL_0061:  stelem.ref
  IL_0062:  ldloc.s    CS$0$0000
  IL_0064:  call       string [mscorlib]System.String::Concat(string[])
  IL_0069:  stloc.1
  IL_006a:  ldloc.2
  IL_006b:  ldc.i4.1
  IL_006c:  add
  IL_006d:  stloc.2
  IL_006e:  ldloc.2
  IL_006f:  ldc.i4     0xf4240
  IL_0074:  blt.s      IL_0016
  IL_0076:  ldloc.0
  IL_0077:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_007c:  ldstr      "testif.txt"
  IL_0081:  ldloc.1
  IL_0082:  call       void [mscorlib]System.IO.File::WriteAllText(string,
                                                                   string)
  IL_0087:  ldloc.0
  IL_0088:  callvirt   instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
  IL_008d:  ret
} // end of method frmResearch::WithOnlyIf

따라서이 포럼에서 많은 사람들이 지적한 것처럼 IF-Else 블록 (블록 # 1)이 if 블록 (블록 # 2)보다 빠르게 실행된다 말할 수 있습니다 .


시험 결과

블록 1 의 10,000,000 회 반복

myFlag = 0:    23.8ns per iteration
myFlag = 1:    23.8ns per iteration

블록 2 의 10,000,000 회 반복

myFlag = 0:    23.8ns per iteration
myFlag = 1:    46.8ns per iteration

블록 2블록 1보다 96 % 느립니다 . 블록 2 는 비관적 인 경우에 두 배의 작업을 수행하기 때문에 의미 가 있습니다.

상황에 따라 어느 쪽이든 선호합니다. 경우 myFlag없는 거의 지금까지 1, 그것은 우리가 처리 해야하는 에지 경우로서 밖으로 서 싶어요 . 둘 다 똑같이 가능성이있는 권한 if-else구문을 원합니다 . 그러나 그것은 사실이 아니라 선호입니다.


다음 명령으로 넘어 가지 않고 멈춤습니다. 사라진 펜티엄 시대에는 CPU는 두 가지 경로를 모두 미리 가져옵니다. 그러나 내 마음 속에는 else에서 가장 일반적인 결과를 가진 코드를 사용할 때마다 여전히 두려움이 있습니다. 더 이상 중요하지 않다는 것을 스스로 상기 할 때마다.


Int32 reps = 10000000;

private void Block1(int myFlag)
{
    String width;
    String height;

    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < reps; i++)
    {
        if (myFlag == 1)
        {
            width = String.Format("{0:g}%", 60);
            height = String.Format("{0:g}%", 60);
        }
        else
        {
            width = String.Format("{0:g}%", 80);
            height = String.Format("{0:g}%", 80);
        }
    }
    sw.Stop();
    Double time = (Double)sw.Elapsed.Ticks / Stopwatch.Frequency * 1000000000.0 / reps;
    MessageBox.Show(time.ToString() + " ns");
}

private void Block2(int myFlag)
{
    String width;
    String height;

    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < reps; i++)
    {
        width = String.Format("{0:g}%", 80);
        height = String.Format("{0:g}%", 80);
        if (myFlag == 1)
        {
            width = String.Format("{0:g}%", 60);
            height = String.Format("{0:g}%", 60);
        }
    }
    sw.Stop();

    Double time = (Double)sw.Elapsed.Ticks / Stopwatch.Frequency * 1000000000.0 / reps;
    MessageBox.Show(time.ToString() + " ns");
}
  • String.Format만드는 IF96 % 속도가 느린
  • GetPercentageString(0.60)만드는 IF96 % 속도가 느린

const
   reps = 10000000;

procedure Block1(myflag: Integer);
var
   width, height: string;
   i: Integer;
   t1, t2: Int64;
   time: Extended;
   freq: Int64;
begin
   QueryPerformanceCounter(t1);
   for i := 1 to reps do
   begin
      if myFlag = 1 then
      begin
         width := '60%';
         height := '60%';
      end
      else
      begin
         width := '80%';
         height := '80%';
      end;
   end;
   QueryPerformanceCounter(t2);
   QueryPerformanceFrequency(freq);

   time := (t2-t1) / freq * 1000000000 / reps;
   ShowMessage(FloatToStr(time)+ 'ns');
end;

procedure Block2(myflag: Integer);
var
   width, height: string;
   i: Integer;
   t1, t2: Int64;
   time: Extended;
   freq: Int64;
begin
   QueryPerformanceCounter(t1);
   for i := 1 to reps do
   begin
      width := '80%';
      height := '80%';
      if myFlag = 1 then
      begin
         width := '60%';
         height := '60%';
      end;
   end;
   QueryPerformanceCounter(t2);
   QueryPerformanceFrequency(freq);

   time := (t2-t1) / freq * 1000000000 / reps;
   ShowMessage(FloatToStr(time)+ 'ns');
end;


두 배의 작업을 수행하는 데는 두 배의 시간이 수행됩니다.

답변 : IF는 IF-ELSE보다 더 잘 수행되지 않습니다.


여기에 이미지 설명 입력


여기에서 성능 향상은 내가 마이크로 마이크로 마이크로 최적화라고 부르는 튜닝에 미미합니다. 이 작업을 몇 백만 번 계획하지 않는 한 여기에서 가독성을 높이십시오.

편집 : (re : 게임에있는 질문)

제 생각에는 첫 번째가 더 읽기. 각 경우에 대한 단순화가 무엇인지 준비된 형식으로 명시 적으로 보여줍니다. 두 번째는 케이스를 검토하는 방법을 검토하여 코드를 결정해야합니다. 원근법을 이해하기 위해 원래 선언 / 초기화 와이 특정 코드 블록 사이에 50 줄의 코드를 상상해. 그 경우에 그것이 불분명 해지면 그것은 나를 위해 그것을 것입니다.


업데이트 됨

Matthew Steeples 답변 에 따라 코드를 업데이트하고 Lou Franco 에 따라 Release 빌드에서 코드를 테스트 한 후 If-Else blcoks가 if 블록보다 성능이 더 우수하다는 것을 알았습니다.

내 테스트 응용 프로그램에서 다음 코드 블록을 사용했습니다.

C # .net 코드

블록 # 1

    public long WithIfAndElse(int myFlag)
    {
        Stopwatch myTimer = new Stopwatch();
        string someString = "";
        myTimer.Start();
        for (int i = 0; i < 1000000; i++)
        {
            string height;
            string width;
            if (myFlag == 1)
            {
                height = "60%";
                width = "60%";
            }
            else
            {
                height = "80%";
                width = "80%";
            }
            someString = "Height: " + height + Environment.NewLine + "Width: " + width;
        }
        myTimer.Stop();
        File.WriteAllText("testifelse.txt", someString);
        return myTimer.ElapsedMilliseconds;
    }

블록 # 2

    public long WithOnlyIf(int myFlag)
    {
        Stopwatch myTimer = new Stopwatch();
        string someString = "";
        myTimer.Start();
        for (int i = 0; i < 1000000; i++)
        {
            string height = "80%";
            string width = "80%";
            if (myFlag == 1)
            {
                height = "60%";
                width = "60%";
            }
            someString = "Height: " + height + Environment.NewLine + "Width: " + width;
        }
        myTimer.Stop();
        File.WriteAllText("testif.txt", someString);
        return myTimer.ElapsedMilliseconds;
    }

다음은 릴리스 빌드의 결과입니다.

1000000 반복에 대한 결과

블록 # 1

myFlag = 1:   1688 Milliseconds
myFlag = 0:   1664 Milliseconds

블록 # 2

myFlag = 1:   1700 Milliseconds
myFlag = 0:   1677 Milliseconds

ildasm.exe에 의해 생성 된 IL 코드

블록 # 1

.method public hidebysig instance int64  WithIfAndElse(int32 myFlag) cil managed
{
  // Code size       144 (0x90)
  .maxstack  3
  .locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
           [1] string someString,
           [2] int32 i,
           [3] string height,
           [4] string width,
           [5] string[] CS$0$0000)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldstr      ""
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_0070
  IL_0016:  ldarg.1
  IL_0017:  ldc.i4.1
  IL_0018:  bne.un.s   IL_0029
  IL_001a:  ldstr      "60%"
  IL_001f:  stloc.3
  IL_0020:  ldstr      "60%"
  IL_0025:  stloc.s    width
  IL_0027:  br.s       IL_0036
  IL_0029:  ldstr      "80%"
  IL_002e:  stloc.3
  IL_002f:  ldstr      "80%"
  IL_0034:  stloc.s    width
  IL_0036:  ldc.i4.5
  IL_0037:  newarr     [mscorlib]System.String
  IL_003c:  stloc.s    CS$0$0000
  IL_003e:  ldloc.s    CS$0$0000
  IL_0040:  ldc.i4.0
  IL_0041:  ldstr      "Height: "
  IL_0046:  stelem.ref
  IL_0047:  ldloc.s    CS$0$0000
  IL_0049:  ldc.i4.1
  IL_004a:  ldloc.3
  IL_004b:  stelem.ref
  IL_004c:  ldloc.s    CS$0$0000
  IL_004e:  ldc.i4.2
  IL_004f:  call       string [mscorlib]System.Environment::get_NewLine()
  IL_0054:  stelem.ref
  IL_0055:  ldloc.s    CS$0$0000
  IL_0057:  ldc.i4.3
  IL_0058:  ldstr      "Width: "
  IL_005d:  stelem.ref
  IL_005e:  ldloc.s    CS$0$0000
  IL_0060:  ldc.i4.4
  IL_0061:  ldloc.s    width
  IL_0063:  stelem.ref
  IL_0064:  ldloc.s    CS$0$0000
  IL_0066:  call       string [mscorlib]System.String::Concat(string[])
  IL_006b:  stloc.1
  IL_006c:  ldloc.2
  IL_006d:  ldc.i4.1
  IL_006e:  add
  IL_006f:  stloc.2
  IL_0070:  ldloc.2
  IL_0071:  ldc.i4     0xf4240
  IL_0076:  blt.s      IL_0016
  IL_0078:  ldloc.0
  IL_0079:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_007e:  ldstr      "testifelse.txt"
  IL_0083:  ldloc.1
  IL_0084:  call       void [mscorlib]System.IO.File::WriteAllText(string,
                                                                   string)
  IL_0089:  ldloc.0
  IL_008a:  callvirt   instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
  IL_008f:  ret
} // end of method frmResearch::WithIfAndElse

블록 # 2

.method public hidebysig instance int64  WithOnlyIf(int32 myFlag) cil managed
{
  // Code size       142 (0x8e)
  .maxstack  3
  .locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
           [1] string someString,
           [2] int32 i,
           [3] string height,
           [4] string width,
           [5] string[] CS$0$0000)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldstr      ""
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_006e
  IL_0016:  ldstr      "80%"
  IL_001b:  stloc.3
  IL_001c:  ldstr      "80%"
  IL_0021:  stloc.s    width
  IL_0023:  ldarg.1
  IL_0024:  ldc.i4.1
  IL_0025:  bne.un.s   IL_0034
  IL_0027:  ldstr      "60%"
  IL_002c:  stloc.3
  IL_002d:  ldstr      "60%"
  IL_0032:  stloc.s    width
  IL_0034:  ldc.i4.5
  IL_0035:  newarr     [mscorlib]System.String
  IL_003a:  stloc.s    CS$0$0000
  IL_003c:  ldloc.s    CS$0$0000
  IL_003e:  ldc.i4.0
  IL_003f:  ldstr      "Height: "
  IL_0044:  stelem.ref
  IL_0045:  ldloc.s    CS$0$0000
  IL_0047:  ldc.i4.1
  IL_0048:  ldloc.3
  IL_0049:  stelem.ref
  IL_004a:  ldloc.s    CS$0$0000
  IL_004c:  ldc.i4.2
  IL_004d:  call       string [mscorlib]System.Environment::get_NewLine()
  IL_0052:  stelem.ref
  IL_0053:  ldloc.s    CS$0$0000
  IL_0055:  ldc.i4.3
  IL_0056:  ldstr      "Width: "
  IL_005b:  stelem.ref
  IL_005c:  ldloc.s    CS$0$0000
  IL_005e:  ldc.i4.4
  IL_005f:  ldloc.s    width
  IL_0061:  stelem.ref
  IL_0062:  ldloc.s    CS$0$0000
  IL_0064:  call       string [mscorlib]System.String::Concat(string[])
  IL_0069:  stloc.1
  IL_006a:  ldloc.2
  IL_006b:  ldc.i4.1
  IL_006c:  add
  IL_006d:  stloc.2
  IL_006e:  ldloc.2
  IL_006f:  ldc.i4     0xf4240
  IL_0074:  blt.s      IL_0016
  IL_0076:  ldloc.0
  IL_0077:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_007c:  ldstr      "testif.txt"
  IL_0081:  ldloc.1
  IL_0082:  call       void [mscorlib]System.IO.File::WriteAllText(string,
                                                                   string)
  IL_0087:  ldloc.0
  IL_0088:  callvirt   instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
  IL_008d:  ret
} // end of method frmResearch::WithOnlyIf

성능 분석기를 사용 하여이 질문에 직접 답하거나 타이밍 만 제출할 수 있습니다. (번 호출하는 루프에 함수를 넣음). 아시다시피 컴파일러는 동일한 코드로 변환합니다 (확인할 수 있음).

아마도 괜찮은 마이크로 최적화에 대해 걱정할 필요가 없습니다. 도구에서 최적화 할 수있는 항목을 알려줄 때까지 가장 읽기 쉬운 코드를 작성하십시오.


앞서 말했듯이 성능은 여기서 문제가되지 않습니다. 가독성에 관심이있는 권한이 다음과 같은 것을 시도해 볼 수 있습니다.

string height = StdHeight;
string width = StdWidth;
if (restrictDimensionsFlag)
{
    height = RestrictedHeight;
    width = RestrictedWidth;
}

표준 및 크기를 다른 곳에서 const 또는 readonlys로 정의합니다.


결과 수정. 나는 내 자신의 테스트를 더 발견했다. 반복 횟수 : 100,000,000

플래그 = 1

여기에 이미지 설명 입력

플래그 = 0.

여기에 이미지 설명 입력

최악의 경우라는 사실은 두 배가 있다는 사실은 있습니다.

사용 된 코드

string height;
string width;
int myFlag = 1;

Console.WriteLine(" ----------- case 1 ---------------");
DateTime Start = DateTime.Now;
for (int Lp = 0; Lp < 100000000; Lp++)
{

    if (myFlag == 1)
    {
        height = "60%";
        width = "60%";
    }
    else
    {
        height = "80%";
        width = "80%";
    }          

}

TimeSpan Elapsed = DateTime.Now - Start;
Console.WriteLine("Time Elapsed: {0} ms",Elapsed.Milliseconds);

Console.WriteLine(" ----------- case 2 ---------------");

DateTime Start2 = DateTime.Now;
for (int Lp = 0; Lp < 100000000; Lp++)
{

    height = "80%";
    width = "80%";

    if (myFlag == 1)
    {
        height = "60%";
        width = "60%";
    }
}

    Elapsed = DateTime.Now - Start2;
    Console.WriteLine("Time Elapsed: {0} ms", Elapsed.Milliseconds);

경고 : 특정 CPU 최적화 작업을 한 지 오래되었습니다.

즉, 어셈블리 언어로 이것을 코딩하면 블록 1은 블록 2보다 루프 당 명령어가 더 적을 것입니다. 어셈블리 / 기계 코드 수준에서 if / else는 if와 비교할 때 본질적으로 자유 롭습니다. 동일한 지침 (로드, 비교, 조건부 점프).

Block1 : 모범 사례 : 5, 최악 : 6

Load value of myFlag
Compare to const 1
Jump if zero (equal)  :t1
  height = "80%";
  width = "80%";
  Jump :t2
:t1
  height = "60%";
  width = "60%";
:t2

Block2 : 모범 사례 : 6, 최악 : 7

height = "80%";
width = "80%";
Load value of myFlag
Compare to const 1
Jump if non-zero (not-equal)  :t1
  height = "60%";
  width = "60%";
:t1

주의 사항 :

  • 모든 명령이 동일하게 생성되는 것은 아니며 특히 어셈블리를 공부할 때 점프 비용이 더 많이 드는 경향이있었습니다. 현대 프로세서는 기본적으로 이러한 경향을 없앴습니다.
  • Modern compilers do a HUGE amount of optimization, and may change the structure of your code from either one of these constructs to the equivalent of the other, or a completely different method entirely. (I've seen some rather creative use of array indices that could be used in cases like this as well)

결론 : 일반적으로 기계어 코드 수준에서도이 두 흐름 간의 차이는 매우 적습니다. 자신에게 가장 잘 맞는 것을 선택하고 컴파일러가이를 최적화하는 가장 좋은 방법을 알아 내도록하십시오. 이와 같은 비교적 사소한 경우는 모두 그렇게 처리해야합니다. 예를 들어 계산 수를 변경하거나 값 비싼 함수 호출을 줄이는 매크로 최적화는 적극적으로 구현해야합니다. 이와 같은 사소한 루프 최적화는 특히 컴파일러가 완료된 후에 실제로 실제 차이를 만들지 않을 것입니다.


이 작업을 수행하는 더 빠른 방법은 아마도 높이와 너비를 int / floats로 처리하고 마지막 순간에 문자열로 캐스팅하는 것입니다 ...이 작업을 원격으로 문제가 될만큼 자주 수행한다고 가정합니다 (힌트 : 그렇지 않습니다).


IL을 보면 if 문이 더 빠른 것보다 더 큰 문제가 있다고 생각합니다. 메서드에 부작용이 없기 때문에 컴파일러는 실제로 디버그 모드에서 if 문의 내용을 완전히 제거하고 릴리스 모드에서 if 문을 완전히 제거합니다.

ILSpy 와 같은 파일에서 .exe 파일을 열면 이를 확인할 수 있습니다.

이 질문에 대한 답을 찾기 전에 알려지고 일정한 시간이 걸리는 무언가로 다시 시작해야합니다.


내가 사용하는 것이 블록의 # 2 . 당신이 말했듯이 성능 저하는 무시할 만하지 만 확실히 더 짧고 읽기 쉽습니다. 기본적으로 특정 조건이 충족되지 않는 한 기본값을 변수로 설정합니다.


블록 # 2가 더 읽을 수 있습니다. 그러나 국제적인 코딩 표준이 있습니까? 가능한 한 많이 공연하거나 지속적인 개선을 제안합니다.

블록 # 1의 성능에 따라 높이와 너비는 null 값으로 초기화 할당됩니다 (조건에 관계없이). 성능 차이가 거의 없습니다.

또한 ILDASM으로 IL을 확인 했습니까?


문제의 변수가 처음에 사용되어 설정되어있는 것이 있기 때문에 일반적으로 Block # 2 방법을 사용합니다.

참고 URL : https://stackoverflow.com/questions/7741033/does-if-perform-better-than-if-else

반응형