배열의`length` 속성을 읽는 것이 자바 스크립트에서 그렇게 비싼 작업입니까?
나는 항상 자바 스크립트에서 배열의 길이를 캐싱하는 것이 (특히 for
루프 의 조건에서 ) 배열의 길이를 계산하는 데 드는 비용 때문에 좋은 생각이라고 생각했습니다 .
예
for (var i = 0; i < arr.length; i++) { }
// vs
for (var i = 0, arrLength = arr.length; i < arrLength; i++) { }
그러나 length
속성은 배열의 생성 및 변경시에만 업데이트 될 것이라고 생각했습니다 . 그러므로 그것을 읽는 것은 변수에 저장된 것을 읽는 것과는 반대로 너무 비싸지 않아야합니다 (예를 들어 strlen()
C에서 무언가의 끝을 찾기 위해 메모리에서 찾아야하는 다른 언어의 다른 방법과는 대조적으로 ).
두 가지 질문이 있습니다. 나는 이것이 어떻게 작동하는지에 관심이 있으므로 조기 최적화 스틱으로 나를 때리지 마십시오 .
브라우저에서 JavaScript 엔진을 가정합니다.
length
JavaScript에서 배열 의 속성 을 캐싱하면 어떤 이점이 있습니까? 객체의 속성에 대한 지역 변수를 읽는 데 훨씬 더 관련이 있습니까?- 는 IS
length
속성은 단순히 생성과에 변경shift()
하고pop()
새로운 배열을 반환하고, 그렇지 않으면 단순히 정수로 저장되지 않는 형식 메서드?
글쎄, 나는 그것이 비싸다고 말했을 것입니다. 그러나 나는 jsperf.com 에서 약간의 테스트를 썼고 놀랍게도 i<array.length
Chrome에서 실제로 사용하는 것이 더 빨랐고 FF (4)에서는 중요하지 않았습니다.
내 의심은 길이가 정수 (Uint32)로 저장된다는 것입니다. ECMA 사양에서 (262 ed. 5, 페이지 121) :
모든 배열 객체는 값이 항상 음이 아닌 정수 2 이상의 길이 속성이있다 (32). 길이 속성의 값은 이름이 배열 인덱스 인 모든 속성의 이름보다 숫자 적으로 더 큽니다. Array 객체의 속성이 생성되거나 변경 될 때마다이 불변을 유지하기 위해 필요에 따라 다른 속성이 조정됩니다. 특히, 이름이 배열 인덱스 인 속성이 추가 될 때마다 길이 속성은 필요한 경우 해당 배열 인덱스의 숫자 값보다 하나 더 많도록 변경됩니다. 그리고 길이 속성이 변경 될 때마다 이름이 배열 인덱스이고 값이 새 길이보다 작지 않은 모든 속성이 자동으로 삭제됩니다. 이 제약은 Array 객체의 고유 속성에만 적용되며 프로토 타입에서 상속 될 수있는 길이 또는 배열 인덱스 속성의 영향을받지 않습니다.
휴! 그런 언어에 익숙해 졌는지 모르겠어요 ...
마지막으로, 우리는 항상 브라우저에 뒤처져 있습니다. IE (9, 8, 7) 캐싱에서는 길이가 정말 빠릅니다. IE를 사용하지 않는 더 많은 이유 중 하나입니다.
TL; DR :
내가 수집 할 수있는 바에 따르면 배열의 길이가 내부적으로 캐시 된 것 같습니다 (적어도 V8에서는).
(자세한 내용은? :))
그래서,이 질문은 제 머릿속에 몇 번 맴돌 았고 저는 문제의 근원에 도달하기로 결정했습니다 (적어도 하나의 구현에서는).
V8 소스를 살펴보면 JSArray 클래스가 생성되었습니다.
// The JSArray describes JavaScript Arrays
// Such an array can be in one of two modes:
// - fast, backing storage is a FixedArray and length <= elements.length();
// Please note: push and pop can be used to grow and shrink the array.
// - slow, backing storage is a HashTable with numbers as keys.
배열 요소의 유형이 빠르거나 느린 지 여부를 결정한다고 가정하고 있습니다. 나는 set_has_fast_elements
( set_bit_field2(bit_field2() | (1 << kHasFastElements))
) 에 설정된 비트 플래그로 내려 갔는데, 여기서 Google 코드를보고 소스가 로컬에 없을 때 파기 선을 그릴 것이라고 생각했습니다.
지금, 그것은 보인다 그 어떤 시간에 어떤 의 하위 클래스입니다 작업이 (배열에서 수행되고 JSObject
, 통화가 이루어집니다 NormalizeElements()
다음을 실행합니다 :
// Compute the effective length.
int length = IsJSArray() ?
Smi::cast(JSArray::cast(this)->length())->value() :
array->length();
따라서 귀하의 질문에 답할 때 :
length
배열 의 속성 을 캐싱하는 데 Chrome (또는 V8을 사용하는 다른 브라우저)에서 어떤 이점도없는 것 같습니다 (slow
그런 조건이 무엇인지 잘 모르겠습니다. )-말했듯이 모든 OS 브라우저 구현을length
통과 할 기회를 얻을 때까지 캐시를 계속할 것입니다.)length
속성은 이후에 변경 될 것으로 보인다 어떤 개체에 대한 작업.
편집하다:
참고로 "빈"배열은 실제로 4 개의 요소를 갖도록 할당 된 것 같습니다.
// Number of element slots to pre-allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
나는 확실히 배열이 범위를 초과 한 번으로 성장하는 방법 많은 요소가 아니에요 - 내가 파고하지 않은 그 깊은 :)
또 다른 성능 테스트 세트 . 루프는 빈 루프가있는 백만 개의 난수 배열에 대해 수행됩니다.
Chrome에서 캐시 된 길이와 캐시되지 않은 길이의 루프는 거의 동일한 시간을 클럭하므로 길이를 캐시하는 것이 V8 최적화 라고 생각합니다 .
Safari 및 Firefox에서 캐시 된 길이는 캐시되지 않은 버전보다 지속적으로 약 2 배 더 빠릅니다.
이 기사에서는 IRHydra 에 생성 된 코드를 요청하여 V8 및 Chrome의 자동 캐싱을 조사 합니다.
How the Grinch stole array.length access by Vyacheslav Egorov
He found that under certain conditions manually caching the .length
actually added overhead rather than improving performance!
But anyway, this kind of micro-optimization is unlikely to achieve any noticeable gain for your users. For their benefit, and for yours, focus instead on code that is clear to read, and using good data structures and algorithms in your code!
Avoid premature optimisation: Focus on elegant code until a performance issue arises. Only then, seek out the bottleneck through profiling, and then optimise just that part of the code.
Just a note:
On some browsers (I've noticed it in Safari, IE, and Opera), you can get a speed boost by caching the length inside the for loop declaration:
var j;
for (var i = 0, len = arr.length; i < len; i++) {
j = arr[i];
}
I edited @KooiInc's jsperf test above to add this case.
Take care not to assume that this is true for all iterable collections. For example caching the length of an HTMLCollection is 65% faster in Chrome (Version 41) and 35% faster in Firefox (Version 36).
'developer tip' 카테고리의 다른 글
행이없는 경우에만 삽입 (0) | 2020.11.15 |
---|---|
MVC 3 jQuery 유효성 검사 / 숫자 / 십진수 필드의 전역 화 (0) | 2020.11.15 |
Zookeeper 3.4.6과 함께 Kafka 0.8.1을 사용할 때 LeaderNotAvailableException으로 실행 (0) | 2020.11.15 |
"삭제 표시"항목은 언제 / 어떻게 최종적으로 제거됩니까? (0) | 2020.11.15 |
Python : 주어진 사용자 이름 / 그룹 이름에 대한 uid / gid 찾기 (os.chown의 경우) (0) | 2020.11.15 |