루프 내부에서 반복적으로 반복되는 것과 달리 루프 전에 버리기 변수를 선언하면 (성능) 차이가 있는지 항상 궁금합니다. Java 의 (무의미한) 예 :
a) 루프 전 선언 :
double intermediateResult;
for(int i=0; i < 1000; i++){
intermediateResult = i;
System.out.println(intermediateResult);
}
b) 루프 내에서 (반복적으로 ) 선언 :
for(int i=0; i < 1000; i++){
double intermediateResult = i;
System.out.println(intermediateResult);
}
어느 것이 더 낫 습니까 , a 또는 b ?
반복되는 변수 선언 (예 : b )이 이론상 더 많은 오버 헤드 를 생성 한다고 생각하지만 컴파일러는 중요하기 때문에 충분히 똑똑합니다. 예제 b 는 더 컴팩트하고 변수의 범위를 사용되는 곳으로 제한한다는 이점이 있습니다. 여전히 예제 a 에 따라 코딩하는 경향이 있습니다 .
편집 : 특히 Java 사례에 관심이 있습니다.
답변
a 또는 b 중 어느 것이 더 낫 습니까?
성능 관점에서 측정해야합니다. (그리고 내 의견으로는, 차이를 측정 할 수 있다면 컴파일러는 좋지 않습니다).
유지 관리 측면에서 b 가 더 좋습니다. 가장 좁은 범위에서 같은 장소에서 변수를 선언하고 초기화하십시오. 선언과 초기화 사이에 간격을 두지 말고 필요하지 않은 네임 스페이스를 오염시키지 마십시오.
답변
글쎄, A 및 B 예제를 각각 20 번 실행하여 1 억 회 반복했습니다. (JVM-1.5.0)
A : 평균 실행 시간 : .074 초
B : 평균 실행 시간 : .067 초
놀랍게도 B는 약간 빨랐습니다. 정확하게 측정 할 수 있다면 컴퓨터가 말을하기가 쉽지 않습니다. 나는 그것을 A 방식으로 코딩 할 것이지만 실제로는 중요하지 않다고 말할 것입니다.
답변
언어와 정확한 사용법에 따라 다릅니다. 예를 들어 C # 1에서는 아무런 차이가 없었습니다. C # 2에서 로컬 변수가 익명 메소드 (또는 C # 3의 람다 식)에 의해 캡처되면 매우 큰 차이를 만들 수 있습니다.
예:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
List<Action> actions = new List<Action>();
int outer;
for (int i=0; i < 10; i++)
{
outer = i;
int inner = i;
actions.Add(() => Console.WriteLine("Inner={0}, Outer={1}", inner, outer));
}
foreach (Action action in actions)
{
action();
}
}
}
산출:
Inner=0, Outer=9
Inner=1, Outer=9
Inner=2, Outer=9
Inner=3, Outer=9
Inner=4, Outer=9
Inner=5, Outer=9
Inner=6, Outer=9
Inner=7, Outer=9
Inner=8, Outer=9
Inner=9, Outer=9
차이점은 모든 조치가 동일한 outer
변수를 캡처 하지만 각각 고유 한 별도의 inner
변수가 있다는 것입니다.
답변
다음은 .NET에서 작성하고 컴파일 한 것입니다.
double r0;
for (int i = 0; i < 1000; i++) {
r0 = i*i;
Console.WriteLine(r0);
}
for (int j = 0; j < 1000; j++) {
double r1 = j*j;
Console.WriteLine(r1);
}
이것이 CIL 이 코드로 다시 렌더링 될 때 .NET Reflector 에서 얻은 것 입니다.
for (int i = 0; i < 0x3e8; i++)
{
double r0 = i * i;
Console.WriteLine(r0);
}
for (int j = 0; j < 0x3e8; j++)
{
double r1 = j * j;
Console.WriteLine(r1);
}
따라서 컴파일 후 둘 다 똑같이 보입니다. 관리되는 언어에서 코드는 CL / 바이트 코드로 변환되고 실행시 기계 언어로 변환됩니다. 따라서 기계 언어에서 이중은 스택에서 생성되지 않을 수도 있습니다. 코드가 WriteLine
함수 의 임시 변수임을 반영하는 레지스터 일 수 있습니다 . 루프에 대해서만 전체 세트 최적화 규칙이 있습니다. 따라서 보통 사람들은 특히 관리되는 언어에서 걱정하지 않아도됩니다. 관리 코드를 최적화 할 수있는 경우가 있습니다. 예를 들어 다음을 사용하여 많은 수의 문자열을 연결해야하는 경우string a; a+=anotherstring[i]
vs 대를 사용StringBuilder
. 둘 다 성능에 큰 차이가 있습니다. 컴파일러가 더 큰 범위의 의도를 파악할 수 없기 때문에 컴파일러가 코드를 최적화 할 수없는 경우가 많이 있습니다. 그러나 기본 사항을 대부분 최적화 할 수 있습니다.
답변
이것은 VB.NET의 문제입니다. 이 예제에서는 Visual Basic 결과가 변수를 다시 초기화하지 않습니다.
For i as Integer = 1 to 100
Dim j as Integer
Console.WriteLine(j)
j = i
Next
' Output: 0 1 2 3 4...
이렇게하면 처음에 0이 인쇄되고 (Visual Basic 변수에는 선언시 기본값이 설정됩니다!) 그 i
이후 에는 매번 출력됩니다.
그러나를 추가하면 = 0
기대할 수있는 것을 얻습니다.
For i as Integer = 1 to 100
Dim j as Integer = 0
Console.WriteLine(j)
j = i
Next
'Output: 0 0 0 0 0...
답변
나는 간단한 테스트를했다 :
int b;
for (int i = 0; i < 10; i++) {
b = i;
}
vs
for (int i = 0; i < 10; i++) {
int b = i;
}
이 코드를 gcc-5.2.0으로 컴파일했습니다. 그런 다음이 두 코드의 기본 ()을 분해하면 결과입니다.
1º :
0x00000000004004b6 <+0>: push rbp
0x00000000004004b7 <+1>: mov rbp,rsp
0x00000000004004ba <+4>: mov DWORD PTR [rbp-0x4],0x0
0x00000000004004c1 <+11>: jmp 0x4004cd <main+23>
0x00000000004004c3 <+13>: mov eax,DWORD PTR [rbp-0x4]
0x00000000004004c6 <+16>: mov DWORD PTR [rbp-0x8],eax
0x00000000004004c9 <+19>: add DWORD PTR [rbp-0x4],0x1
0x00000000004004cd <+23>: cmp DWORD PTR [rbp-0x4],0x9
0x00000000004004d1 <+27>: jle 0x4004c3 <main+13>
0x00000000004004d3 <+29>: mov eax,0x0
0x00000000004004d8 <+34>: pop rbp
0x00000000004004d9 <+35>: ret
vs
2º
0x00000000004004b6 <+0>: push rbp
0x00000000004004b7 <+1>: mov rbp,rsp
0x00000000004004ba <+4>: mov DWORD PTR [rbp-0x4],0x0
0x00000000004004c1 <+11>: jmp 0x4004cd <main+23>
0x00000000004004c3 <+13>: mov eax,DWORD PTR [rbp-0x4]
0x00000000004004c6 <+16>: mov DWORD PTR [rbp-0x8],eax
0x00000000004004c9 <+19>: add DWORD PTR [rbp-0x4],0x1
0x00000000004004cd <+23>: cmp DWORD PTR [rbp-0x4],0x9
0x00000000004004d1 <+27>: jle 0x4004c3 <main+13>
0x00000000004004d3 <+29>: mov eax,0x0
0x00000000004004d8 <+34>: pop rbp
0x00000000004004d9 <+35>: ret
어느 asa 결과와 같은 asm 결과입니다. 두 코드가 동일한 것을 생성한다는 증거가 아닙니까?
답변
언어에 따라 다릅니다. IIRC C #은이를 최적화하므로 차이는 없지만 JavaScript (예 : JavaScript)는 매번 전체 메모리 할당을 수행합니다.