124 votes

Pourquoi est la concaténation de chaîne plus rapide que la matrice de les rejoindre?

Aujourd'hui, j'ai lu ce fil sur la vitesse de la concaténation de chaîne.

Étonnamment, la concaténation de chaîne a été le vainqueur:

http://jsperf.com/array-join-vs-string-connect

http://jsperf.com/join-concat/2

Le résultat était à l'opposé de ce que je pensais. En outre, il existe de nombreux articles sur ce qui explique opposée, comme ceci ou cela.

Je peux deviner que les navigateurs sont optimisés pour la chaîne concat sur la dernière version, mais comment font-ils cela? Peut-on dire qu'il est préférable d'utiliser + lors de la concaténation de chaînes de caractères?

153voto

Daan Points 3325

Chaîne de navigateur optimisations ont changé la concaténation de chaîne de l'image.

Firefox a été le premier navigateur à optimiser la concaténation de chaîne. À partir de la version 1.0, le tableau technique est effectivement plus lent que d'utiliser l'opérateur+. dans tous les cas. Les autres navigateurs ont également optimisé la concaténation de chaîne, donc, Safari, Opera, Chrome, et Internet Explorer 8 montrent également de meilleures performances à l'aide de l'opérateur plus. Internet Explorer avant la version 8 n'ont pas une telle optimisation, et donc la matrice technique est toujours plus rapide que l'opérateur plus.

- Écriture Efficace JavaScript: Chapitre 7 – Encore Plus Rapide Des Sites Web

Le moteur javascript V8 (Google Chrome) utilise ce code pour faire la concaténation de chaîne:

// 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, "");
}

Donc, en interne, ils l'optimiser par la création d'un InternalArray ( parts variable), qui est ensuite rempli. Le StringBuilderConcat fonction est appelée avec ces pièces. C'est rapide, car la StringBuilderConcat fonction est certains fortement optimisé le code C++. C'est trop long de citer ici, mais la recherche dans le runtime.cc fichier pour RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) voir le code.

26voto

evilpie Points 1082

Firefox est rapide car il utilise ce qu'on appelle des Cordes (Cordes: une Alternative aux des Chaînes). Une corde est fondamentalement juste un DAG, où chaque Nœud est une chaîne de caractères.

Ainsi, par exemple, si vous n' a = 'abc'.concat('def'), l'objet nouvellement créé devrait ressembler à ceci. Bien sûr, ce n'est pas exactement ce que cela ressemble à la mémoire, parce que vous avez encore besoin d'avoir un champ de type chaîne de caractères, de longueur et peut-être d'autres.

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

Et b = a.concat('123')

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

Ainsi, dans le cas le plus simple de la VM doit faire presque pas de travail. Le seul problème est que cela ralentit les autres opérations de la chaîne résultante un peu. Aussi bien sûr, cela réduit la surcharge de la mémoire.

D'autre part ['abc', 'def'].join('') habituellement juste allouer de la mémoire pour la disposition de la nouvelle chaîne de télévision en mémoire. (Peut-être cela devrait être optimisé)

2voto

xanatos Points 30513

Je dirais qu'avec des cordes, il est plus facile de préallouer une plus grande mémoire tampon. Chaque élément est à seulement 2 octets (si UNICODE), de sorte que même si vous êtes conservateur, vous pouvez préallouer un assez gros tampon pour la chaîne. Avec arrays chaque élément est plus "complexe", car chaque élément est un Object, alors conservateur de la mise en œuvre sera préallouer l'espace de moins d'éléments.

Si vous essayez d'ajouter un for(j=0;j<1000;j++) avant chaque for vous allez voir que (sous chrome) la différence de vitesse devient plus petit. En fin de compte, il était encore 1,5 x pour la concaténation de chaîne, mais de plus petite taille que les 2,6 c'était avant.

ET d'avoir à copier les éléments, un caractère Unicode est probablement moins important que d'une référence à un Objet JS.

Sachez qu'il y a la possibilité que de nombreuses implémentations de JS moteurs d'une optimisation pour un seul type de tableaux que j'ai écrit inutile :-)

1voto

srgstm Points 432

Ce test montre que la pénalité de fait à l'aide d'une corde faite avec attribution de la concaténation vs faite avec le tableau.méthode de participation. Alors que la vitesse globale de l'affectation est encore deux fois plus vite dans Chrome v31 mais il n'est plus aussi énorme que lorsque vous n'utilisez pas la chaîne résultante.

-1voto

Marcelo Cantos Points 91211

Ma conjecture est que, bien que chaque version est de porter le coût de nombreux précédents, la jointure sont les versions de construire les tableaux en plus de cela.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X