Je me posais des questions sur StringBuilder et j'ai une question que j'espérais que la communauté serait en mesure de l'expliquer.
Oublions simplement la lisibilité du code, laquelle est plus rapide et pourquoi?
StringBuilder.Append
:StringBuilder sb = new StringBuilder();
sb.Append(string1);
sb.Append("----");
sb.Append(string2);
StringBuilder.AppendFormat
:StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}----{1}",string1,string2);
Il est impossible de dire, ne connaissant pas la taille de string1
et string2
.
Avec l'appel à AppendFormat
, il préallouera le tampon une seule fois, en fonction de la longueur de la chaîne de formatage et des chaînes à insérer, puis tout concaténer et l'insérer dans le tampon. Pour les très grandes chaînes, cela sera avantageux par rapport aux appels séparés à Append
, ce qui pourrait entraîner le développement de la mémoire tampon plusieurs fois.
Cependant, les trois appels à Append
peuvent ou non déclencher une croissance de la mémoire tampon et cette vérification est effectuée à chaque appel. Si les chaînes sont suffisamment petites et qu'aucune expansion de mémoire tampon n'est déclenchée, le processus sera plus rapide que l'appel à AppendFormat
car il ne sera pas nécessaire d'analyser la chaîne de format pour déterminer où effectuer les remplacements.
Plus de données sont nécessaires pour une réponse définitive
Il convient de noter qu’il est peu question d’utiliser la méthode static Concat
SUR LA CLASSE String
( La réponse de Jon using AppendWithCapacity
m’a rappelé cela). Les résultats de ses tests montrent que c'est le meilleur des cas (en supposant que vous n'avez pas à tirer parti d'un spécificateur de format spécifique). String.Concat
fait la même chose en ce sens qu'il prédétermine la longueur des chaînes à concaténer et préallouer le tampon (avec un peu plus de temps système dû aux constructions en boucle dans les paramètres). Ses performances seront comparables à la méthode AppendWithCapacity
de Jon.
Ou simplement l'opérateur d'ajout brut, puisqu'il compile un appel à String.Concat
de toute façon, avec l'avertissement que tous les ajouts sont dans la même expression:
// One call to String.Concat.
string result = a + b + c;
NE PAS
// Two calls to String.Concat.
string result = a + b;
result = result + c;
Pour tous ceux qui mettent en place le code de test
Vous devez exécuter vos scénarios de test dans des exécutions distinctes (ou au moins, effectuer un GC entre les mesures de tests distincts). La raison en est que si vous dites que 1 000 000 de tests sont créés, créant un nouveau StringBuilder
à chaque itération de la boucle pour un test, puis vous exécutez le test suivant qui boucle le même nombre de fois, créant ainsi un supplémentaire 1 000 000 StringBuilder
instances, le GC interviendra très probablement lors du deuxième test et en empêchera le chronométrage.
casperOne est correct . Une fois que vous atteignez un certain seuil, la méthode Append()
devient plus lente que AppendFormat()
. Voici les différentes longueurs et les ticks écoulés de 100 000 itérations de chaque méthode:
Append() - 50900
AppendFormat() - 126826
Append() - 1241938
AppendFormat() - 1337396
Append() - 12482051
AppendFormat() - 12740862
Append() - 61029875
AppendFormat() - 60483914
Lorsque des chaînes d'une longueur proche de 20 000 sont introduites, la fonction AppendFormat()
va légèrement surpasser Append()
.
Pourquoi cela arrive-t-il? Voir Réponse de casperOne .
Modifier:
Je répète chaque test individuellement sous Configuration de la version et mets à jour les résultats.
Append
sera plus rapide dans la plupart des cas car il existe de nombreuses surcharges dans cette méthode qui permettent au compilateur d'appeler la bonne méthode. Puisque vous utilisez Strings
, StringBuilder
peut utiliser la surcharge String
pour Append
.
AppendFormat
prend une String
puis un Object[]
, ce qui signifie que le format devra être analysé et que chaque Object
du tableau devra être ToString'd
avant de pouvoir être ajouté au tableau interne StringBuilder's
.
Note: Au point de casperOne - il est difficile de donner une réponse exacte sans plus de données.
StringBuilder
a également ajouté en cascade: Append()
renvoie la StringBuilder
elle-même, vous pouvez donc écrire votre code comme suit:
StringBuilder sb = new StringBuilder();
sb.Append(string1)
.Append("----")
.Append(string2);
Propre et génère moins de code IL (bien que ce soit vraiment une micro-optimisation).
Bien sûr profilez pour savoir à coup sûr dans chaque cas.
Cela dit, je pense que ce sera généralement le premier car vous n'analyserez pas la chaîne de format à plusieurs reprises.
Cependant, la différence serait très petite. Au point que vous devriez vraiment envisager d'utiliser AppendFormat
dans la plupart des cas de toute façon.
Je suppose que c'est l'appel qui a fait le moins de travail. Append ne fait que concaténer des chaînes, où AppendFormat effectue des substitutions de chaînes. Bien sûr, ces jours-ci, on ne peut jamais dire ...
1 devrait être plus rapide car il s'agit simplement d'ajouter des chaînes alors que 2 doit créer une chaîne basée sur un format, puis l'ajouter. Donc, il y a un pas supplémentaire là-dedans.
Plus rapide est 1 dans votre cas, mais ce n'est pas une comparaison juste. Vous devez demander à StringBuilder.AppendFormat () vs StringBuilder.Append (string.Format ()) - où le premier est plus rapide en raison du travail interne avec le tableau de caractères.
Votre deuxième option est plus lisible cependant.