[javascript] 루프가 반대로 더 빠릅니까?

나는 이것을 꽤 많이 들었다. 역으로 계산할 때 JavaScript 루프가 실제로 더 빠릅니까? 그렇다면 왜 그렇습니까? 역 루프가 빠르다는 것을 보여주는 몇 가지 테스트 스위트 예제를 보았지만 그 이유에 대한 설명을 찾을 수 없습니다!

루프가 더 이상 완료되었는지 확인하고 최종 숫자 값과 비교하여 확인할 때마다 더 이상 속성을 평가할 필요가 없기 때문에 가정합니다.

for (var i = count - 1; i >= 0; i--)
{
  // count is only evaluated once and then the comparison is always on 0.
}



답변

그것 i--보다 빠르지는 않습니다 i++. 사실, 둘 다 똑같이 빠릅니다.

오름차순 루프에서 시간이 걸리는 것은 각각 i의 배열 크기를 평가 하는 것입니다. 이 루프에서 :

for(var i = array.length; i--;)

이 루프의 .length경우 선언 할 때 한 번만 평가 합니다.i

for(var i = 1; i <= array.length; i++)

검사 할 때 .length마다 증분 i할 때 마다 평가 합니다 i <= array.length.

대부분의 경우 이러한 종류의 최적화에 대해 걱정하지 않아도 됩니다.


답변

이 사람 은 많은 브라우저에서 자바 스크립트의 많은 루프를 비교했습니다. 그는 또한 테스트 스위트를 가지고 있으므로 직접 실행할 수 있습니다.

모든 경우에 (내 읽기에서 하나를 놓치지 않는 한) 가장 빠른 루프는 다음과 같습니다.

var i = arr.length; //or 10
while(i--)
{
  //...
}


답변

나는이 답변으로 넓은 그림을 제시하려고합니다.

최근에 문제를 테스트 할 때까지 괄호 안에 다음과 같은 생각이 있었습니다 .

[[ C / C ++ 와 같은 저수준 언어의 관점에서 , 변수가 0이거나 0이 아닌 경우 프로세서가 특수한 조건부 점프 명령을 갖도록 코드가 컴파일됩니다.
또한 이처럼 많은 최적화 가 필요한 경우 단일 프로세서 명령이 아니라을 의미 하기 때문에 대신 대신 갈 수 있습니다.]]
++ii++++ii++j=i+1, i=j

롤을 풀면 정말 빠른 루프를 수행 할 수 있습니다.

for(i=800000;i>0;--i)
    do_it(i);

보다 느려질 수 있습니다

for(i=800000;i>0;i-=8)
{
    do_it(i); do_it(i-1); do_it(i-2); ... do_it(i-7);
}

그러나 그 이유는 상당히 복잡 할 수 있습니다 (단, 게임에서 프로세서 명령 사전 처리 및 캐시 처리 문제가 있음).

요청한 JavaScript 와 같은 고급 언어의 관점 에서 라이브러리를 사용하는 경우 루프를위한 내장 함수를 최적화 할 수 있습니다. 최선의 방법을 결정하게하십시오.

결과적으로 JavaScript에서는 다음과 같은 것을 사용하는 것이 좋습니다.

array.forEach(function(i) {
    do_it(i);
});

또한 오류가 적으며 브라우저는 코드를 최적화 할 수 있습니다.

[비고 : 브라우저뿐만 아니라 쉽게 최적화 할 수있는 공간도 있습니다 forEach. 최신 브라우저를 사용하도록 기능 (브라우저에 따라 다름)을 재정의하기 만하면됩니다 ! 🙂 @AMK 오히려 사용 가치가있다 특별한 경우라고 array.pop하거나 array.shift. 그렇게하면 커튼 뒤에 놓으십시오. 최대한 과잉은 에 옵션을 추가하는 것입니다 forEach루핑 알고리즘을 선택할 수 있습니다.]

또한 저수준 언어의 경우 가능하면 복잡한 루프 작업에 스마트 라이브러리 기능을 사용하는 것이 가장 좋습니다.

이러한 라이브러리는 또한 멀티 스레드 방식으로 작업을 수행 할 수 있으며 전문 프로그래머가 최신 상태로 유지할 수 있습니다.

좀 더 면밀히 조사했으며 C / C ++에서는 5e9 = (50,000×100,000) 연산의 경우에도 @alestanis와 같이 상수에 대해 테스트를 수행하면 위아래로 차이가 없다는 것을 알 수 있습니다. (JsPerf 결과는 때때로 일치하지 않지만 대체로 동일하게 말합니다. 큰 차이를 만들 수는 없습니다.)
따라서 --i“포쉬 한”것입니다. 더 나은 프로그래머처럼 보일뿐입니다. 🙂

다른 한편으로,이 5e9 상황에서 풀리려면 10 초가되면 12 초에서 2.5 초로, 20 초가되면 2.1 초로 줄었습니다. 최적화가 없었고 최적화로 인해 측정 할 수없는 작은 시간이되었습니다. 🙂 (언 롤링은 위의 방식으로 또는를 사용하여 수행 할 수 i++있지만 JavaScript에서 앞으로 나아갈 수는 없습니다.)

모두 모두 : KEEP i--/ i++++i/ i++직업 인터뷰, 스틱에 차이가 array.forEach사용할 수 없거나 다른 복잡한 라이브러리 함수. 😉


답변

i-- ~만큼 빠르다 i++

아래 코드는 귀하의 것보다 빠르지 만 추가 변수를 사용합니다.

var up = Things.length;
for (var i = 0; i < up; i++) {
    Things[i]
};

권장 사항은 매번 어레이의 크기를 평가하지 않는 것입니다. 큰 어레이의 경우 성능 저하를 볼 수 있습니다.


답변

주제에 관심이 있으니 JavaScript 루프 벤치 마크인 JavaScript에서 루프를 코딩 하는 가장 빠른 방법은 무엇입니까 에 대한 Greg Reimer의 웹 로그 게시물을 살펴보십시오 . :

JavaScript에서 루프를 코딩하는 다양한 방법을위한 루프 벤치마킹 테스트 스위트를 구축했습니다. 이미 몇 가지가 있지만 네이티브 배열과 HTML 컬렉션의 차이점을 인정하는 것을 찾지 못했습니다.

또한 열어서 루프에서 성능 테스트를 수행 할 수 있습니다 https://blogs.oracle.com/greimer/resource/loop-test.html(예 : NoScript 등으로 브라우저에서 JavaScript가 차단 된 경우 작동하지 않음 ).

편집하다:

밀라노 Adamovsky에 의해 생성 된 최근의 벤치 마크 실행시에 수행 할 수 있습니다 여기에 다른 브라우저.

A의 맥 OS X에서 파이어 폭스 17.0에서 테스트 10.6 나는 다음과 같은 루프를 가지고 :

var i, result = 0;
for (i = steps - 1; i; i--) {
  result += i;
}

가장 빠른 선행 :

var result = 0;
for (var i = steps - 1; i >= 0; i--) {
  result += i;
}

벤치 마크 예.


답변

--또는 아닌 ++, 비교 작업입니다. 를 사용 --하면 0과 비교를 사용할 수 있지만 ++길이와 비교해야합니다. 프로세서에서 0과 비교는 일반적으로 사용 가능하지만 유한 정수와 비교하려면 빼기가 필요합니다.

a++ < length

실제로 다음과 같이 컴파일됩니다

a++
test (a-length)

따라서 컴파일 할 때 프로세서에서 시간이 더 걸립니다.


답변

짧은 답변

일반 코드, 특히 JavaScript 와 같은 고급 언어의 경우 i++및에 성능 차이가 없습니다 i--.

성능 기준은 for루프 및 비교 에서의 사용입니다. 문.

이것은 모든 고급 언어에 적용되며 대부분 JavaScript 사용과 무관합니다. 결론은 최종 결과 어셈블러 코드입니다.

상해

루프에서 성능 차이가 발생할 수 있습니다. 배경은에 있다는 것입니다 어셈블러 코드 수준 당신이이 것을 볼 수 있습니다 compare with 0추가 등록이 필요하지 않습니다 하나의 문입니다.

이 비교는 루프의 모든 패스에서 발행되며 성능이 크게 향상 될 수 있습니다.

for(var i = array.length; i--; )

다음 과 같은 의사 코드 로 평가됩니다 .

 i=array.length
 :LOOP_START
 decrement i
 if [ i = 0 ] goto :LOOP_END
 ... BODY_CODE
 :LOOP_END

참고 0 리터, 바꾸어 말하면, 일정한 값이된다.

for(var i = 0 ; i < array.length; i++ )

다음 과 같은 의사 코드 로 평가됩니다 (일반 인터프리터 최적화 가정).

 end=array.length
 i=0
 :LOOP_START
 if [ i < end ] goto :LOOP_END
 increment i
 ... BODY_CODE
 :LOOP_END

참고 단부 필요한 변수 CPU의 레지스터. 이는 코드에서 추가 레지스터 스와핑 을 호출 할 수 있으며 명령문 에서 더 비싼 비교문이 필요합니다 if.

내 5 센트 만

고급 언어의 경우 약간의 성능 향상으로 유지 관리가 용이 ​​한 가독성이 더 중요합니다.

일반적으로 배열 시작부터 끝까지 고전적인 반복 이 더 좋습니다.

배열 끝에서 시작하여 반복이 빠를 수록 원하지 않는 반전 순서가 발생할 수 있습니다.

포스트 스크립트

의견에서 묻는 것처럼 : 감소 전후 의 차이점 --ii--평가에 i있습니다.

가장 좋은 설명은 시도해 보는 것입니다. 😉 여기 Bash 예제가 있습니다.

 % i=10; echo "$((--i)) --> $i"
 9 --> 9
 % i=10; echo "$((i--)) --> $i"
 10 --> 9