[javascript] 문자열 연결이 배열 결합보다 빠른 이유는 무엇입니까?

오늘 저는 문자열 연결 속도에 대해이 글을 읽었습니다 .

놀랍게도 문자열 연결이 승자였습니다.

http://jsben.ch/#/OJ3vo

결과는 제가 생각했던 것과 반대였습니다. 게다가, 같은 반대로 설명이에 대한 많은 기사가 .

브라우저가 concat최신 버전의 문자열 에 최적화되어 있다고 생각할 수 있지만 어떻게 그렇게합니까? +문자열을 연결할 때 사용하는 것이 더 낫다고 말할 수 있습니까 ?


최신 정보

따라서 최신 브라우저에서는 문자열 연결이 최적화되어 있으므로 +기호를 사용 join하는 것이 문자열 을 연결 하려는 경우 보다 빠릅니다 .

그러나 @Arthur는 지적join빨리 당신이 실제로하고 싶은 경우입니다 가입 구분와 문자열을.


업데이트-2020
Chrome : 배열 join은 거의 2 times faster문자열 연결입니다. +
참조 : https://stackoverflow.com/a/54970240/984471

참고로 :

  • join당신이 가지고 있다면 배열 이 더 좋습니다large strings
  • several small strings최종 출력에서 생성 이 필요한 경우 string concat을 사용하는 것이 좋습니다. +그렇지 않으면 Array를 사용하려면 끝에 여러 개의 Array to String 변환이 필요하므로 성능 오버로드가 필요합니다.



답변

브라우저 문자열 최적화로 인해 문자열 연결 그림이 변경되었습니다.

Firefox는 문자열 연결을 최적화 한 최초의 브라우저입니다. 버전 1.0부터 배열 기술은 실제로 모든 경우에 더하기 연산자를 사용하는 것보다 느립니다. 다른 브라우저도 문자열 연결을 최적화했기 때문에 Safari, Opera, Chrome 및 Internet Explorer 8도 더하기 연산자를 사용하여 더 나은 성능을 보여줍니다. 버전 8 이전의 Internet Explorer에는 이러한 최적화 기능이 없었으므로 배열 기술은 항상 더하기 연산자보다 빠릅니다.

효율적인 JavaScript 작성 : 7 장 – 더 빠른 웹 사이트

V8 자바 스크립트 엔진 (Google 크롬에서 사용됨)은 다음 코드 를 사용 하여 문자열 연결을 수행합니다.

// ECMA-262, section 15.5.4.6
function StringConcat() {
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);
  }
  var len = %_ArgumentsLength();
  var this_as_string = TO_STRING_INLINE(this);
  if (len === 1) {
    return this_as_string + %_Arguments(0);
  }
  var parts = new InternalArray(len + 1);
  parts[0] = this_as_string;
  for (var i = 0; i < len; i++) {
    var part = %_Arguments(i);
    parts[i + 1] = TO_STRING_INLINE(part);
  }
  return %StringBuilderConcat(parts, len + 1, "");
}

따라서 내부적으로는 InternalArray ( parts변수) 를 생성하여이를 최적화 한 다음 채워집니다. StringBuilderConcat 함수는 이러한 부분과 함께 호출됩니다. StringBuilderConcat 함수는 고도로 최적화 된 C ++ 코드이기 때문에 빠릅니다. 여기에 인용하기에는 너무 길지만 코드를 보려면 runtime.cc 파일 에서 검색 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat)하십시오.


답변

Firefox는 Ropes ( Ropes : an Alternative to Strings ) 라는 것을 사용하기 때문에 빠릅니다 . 로프는 기본적으로 모든 노드가 문자열 인 DAG입니다.

예를 들어를하면 a = 'abc'.concat('def')새로 생성 된 객체는 다음과 같습니다. 물론 이것이 메모리에서 정확히 어떻게 보이는지가 아닙니다. 문자열 유형, 길이 및 기타에 대한 필드가 필요하기 때문입니다.

a = {
 nodeA: 'abc',
 nodeB: 'def'
}

b = a.concat('123')

b = {
  nodeA: a, /* {
             nodeA: 'abc',
             nodeB: 'def'
          } */
  nodeB: '123'
}           

따라서 가장 간단한 경우 VM은 거의 작업을 수행하지 않아도됩니다. 유일한 문제는 결과 문자열에 대한 다른 작업이 약간 느려진다는 것입니다. 또한 이것은 물론 메모리 오버 헤드를 줄입니다.

반면에 ['abc', 'def'].join('')일반적으로 메모리를 할당하여 새 문자열을 메모리에 평평하게 배치합니다. (최적화되어야 할 수도 있음)


답변

이것이 오래된 스레드라는 것을 알고 있지만 테스트가 잘못되었습니다. 잊었 기 때문에 물건을 무언가와 함께 붙이는 output += myarray[i];것과 비슷해야하는 동안 당신은하고 있습니다 output += "" + myarray[i];. 연결 코드는 다음과 같아야합니다.

var output = myarray[0];
for (var i = 1, len = myarray.length; i<len; i++){
    output += "" + myarray[i];
}

그런 식으로 요소를 함께 붙이기 때문에 하나가 아닌 두 가지 작업을 수행합니다.

Array.join() 가 더 빠르다.


답변

많은 양의 데이터 결합이 더 빠르기 때문에 질문이 잘못 설명됩니다.

let result = "";
let startTime = new Date().getTime();
for (let i = 0; i < 2000000; i++) {
    result += "x";
}
console.log("concatenation time: " + (new Date().getTime() - startTime));

startTime = new Date().getTime();
let array = new Array(2000000);
for (let i = 0; i < 2000000; i++) {
    array[i] = "x";
}
result = array.join("");
console.log("join time: " + (new Date().getTime() - startTime));

Chrome 72.0.3626.119, Firefox 65.0.1, Edge 42.17134.1.0에서 테스트되었습니다. 어레이 생성이 포함되어 있어도 더 빠릅니다!


답변

벤치 마크는 사소합니다. 동일한 세 항목을 반복적으로 연결하면 인라인 처리되고 결과는 결정적이고 메모되며, 가비지 처리기는 배열 객체 (크기가 거의 없음)를 버리고 아마도 스택에서 밀어 내고 튀어 나올 것입니다. 외부 참조와 문자열이 절대 변경되지 않기 때문입니다. 테스트가 무작위로 생성 된 문자열이 많으면 더 인상적 일 것입니다. 공연이나 2 분의 문자열처럼.

Array.join FTW!


답변

문자열을 사용하면 더 큰 버퍼를 미리 할당하는 것이 더 쉽습니다. 각 요소는 2 바이트 (UNICODE 인 경우)에 불과하므로 보수적 인 경우에도 문자열에 대해 꽤 큰 버퍼를 미리 할당 할 수 있습니다. 로 arrays각 요소를이 때문에 각 원소보다 “복합체”인 Object보수적 구현이 적은 요소를위한 공간을 미리 할당 할 수 있도록한다.

for(j=0;j<1000;j++)각각 앞에 a를 추가하려고하면 for(크롬 아래에서) 속도 차이가 작아지는 것을 알 수 있습니다. 결국 문자열 연결의 경우 여전히 1.5 배 였지만 이전 2.6보다 작았습니다.

요소를 복사해야하는 경우 유니 코드 문자는 JS 개체에 대한 참조보다 작을 수 있습니다.

JS 엔진의 많은 구현이 내가 작성한 모든 것을 쓸모 없게 만드는 단일 유형 배열에 대한 최적화를 가질 가능성이 있음을 유의하십시오 🙂


답변

이 테스트 는 할당 연결로 만든 문자열과 array.join 메서드로 만든 문자열을 실제로 사용할 때의 패널티를 보여줍니다. 전체 할당 속도는 Chrome v31에서 여전히 두 배 빠르지 만 결과 문자열을 사용하지 않을 때만 큼 크지는 않습니다.