Почему конкатенация строк выполняется быстрее, чем объединение массивов?



сегодня я прочитал эту тему о скорости конкатенации строк.



Удивительно, но конкатенация строк была победителем:




http://jsben.ch/#/OJ3vo




результат был противоположен тому, что я думал. Кроме того, есть много статей об этом, которые объясняют противоположно, как этой.



Я могу догадаться, что браузеры оптимизированы для string concat на последней версии, но как это сделать они так делают? Можно сказать, что лучше использовать + при конкатенации строк?



обновление



Итак, в современных браузерах конкатенация строк оптимизирована таким образом, используя + знаки быстрее, чем с помощью join Если вы хотите объединения строки.



но @Arthur указал на это join быстрее, если вы на самом деле хотите вступить строки с разделителем.

649   8  

8 ответов:

оптимизация строк браузера изменила изображение конкатенации строк.

Firefox был первым браузером для оптимизации конкатенации строк. Начиная с версии 1.0, метод массива на самом деле медленнее, чем использование оператора plus во всех случаях. Другие браузеры также оптимизировали конкатенацию строк, поэтому Safari, Opera, Chrome и Internet Explorer 8 также показывают лучшую производительность с помощью оператора plus. Internet Explorer до версии 8 не сделал есть такая оптимизация, и поэтому метод массива всегда быстрее, чем оператор plus.

-Написание Эффективного JavaScript: Глава 7-Еще Более Быстрые Веб-Сайты

движок V8 javascript (используется в Google Chrome) использует код чтобы выполнить конкатенацию строк:

// 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 (the parts переменная), которая затем заполняется. В StringBuilderConcat функция вызывается с помощью этих частей. Это быстро, потому что функция StringBuilderConcat-это сильно оптимизированный код на C++. Это слишком долго, чтобы цитировать здесь, но поиск в runtime.cc файл для RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) чтобы увидеть код.

Firefox быстро, потому что он использует что-то под названием веревки (веревки: альтернатива струнам). Веревка-это в основном просто DAG, где каждый узел-это строка.

так например, если бы вы сделали a = 'abc'.concat('def') вновь созданный объект будет выглядеть так. конечно, это не совсем так, как это выглядит в памяти, потому что вам все равно нужно иметь поле для типа строки, длины и, возможно, других.

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

и b = a.concat('123')

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

поэтому в простейшем случае виртуальная машина почти не работает. Единственная проблема заключается в том, что это немного замедляет другие операции над результирующей строкой. Кроме того, это, конечно, уменьшает накладные расходы памяти.

С другой стороны ['abc', 'def'].join('') обычно просто выделяют память, чтобы выложить новую строку в памяти. (Возможно, это должно быть оптимизировано)

Я знаю, что это старый нить, но ваш тест некорректен. Вы делаете output += myarray[i]; а это должно быть больше как output += "" + myarray[i]; потому что вы забыли, что вы должны склеить элементы вместе с чем-то. Код concat должен быть примерно таким:

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

таким образом, Вы делаете две операции вместо одной из-за склейки элементов между собой.

Array.join() - это быстрее.

ориентиры там тривиальные. Объединение одних и тех же трех элементов повторно будет встроено, результаты будут доказаны детерминированными и запомненными, обработчик мусора будет просто выбрасывать объекты массива (которые будут почти ничего по размеру) и, вероятно, просто выталкивать и выскакивать из стека из-за отсутствия внешних ссылок и потому, что строки никогда не меняются. Я был бы более впечатлен, если бы тест был большим количеством случайно сгенерированных строк. Как в концерте или два стоит веревка.

массив.присоединиться к США.

Я бы сказал, что со струнами легче выделить больший буфер. Каждый элемент составляет всего 2 байта (если UNICODE), поэтому даже если вы консервативны, вы можете предварительно выделить довольно большой буфер для строки. С arrays каждый элемент является более "сложным", потому что каждый элемент-это Object, поэтому консервативная реализация будет предварительно выделять пространство для меньшего количества элементов.

если вы попытаетесь добавить for(j=0;j<1000;j++) перед каждым for вы увидите, что (под chrome) разница в скорости становится меньше. В конце концов это было еще 1.5 x для конкатенации строк, но меньше, чем 2.6, что было раньше.

и, чтобы скопировать элементы, символ Юникода, вероятно, меньше, чем ссылка на объект JS.

имейте в виду, что существует вероятность того, что многие реализации JS-движков имеют оптимизацию для однотипных массивов, которые сделают все, что я написал, бесполезным :-)

этот тест показывает штраф за фактическое использование строки, сделанной с конкатенацией присваивания, против сделанной с массивом.метод соединения. В то время как общая скорость назначения по-прежнему в два раза быстрее в Chrome v31, но она уже не так велика, как при использовании результирующей строки.

это явно зависит от реализации движка javascript. Даже для разных версий одного движка можно получить существенно разные результаты. Вы должны сделать свой собственный тест, чтобы проверить это.

Я бы сказал, что String.concat имеет лучшую производительность в последних версиях V8. Но для Firefox и Opera, Array.join победитель.

Я предполагаю, что, хотя каждая версия несет стоимость многих конкатенаций, версии соединения строят массивы в дополнение к этому.

Comments

    Ничего не найдено.