web-dev-qa-db-fra.com

Concaténation de chaînes vs constructeur de chaînes. Performance

J'ai une situation où j'ai besoin de concaténer plusieurs chaînes pour former un identifiant d'une classe. Fondamentalement, je boucle dans une liste pour obtenir les valeurs ToString des objets, puis les concaténer.

foreach (MyObject o in myList)
  result += o.ToString();

La liste ne devrait PAS comporter plus de 5 éléments (bien qu'elle puisse l'être mais c'est un cas très très marginal) et comportera généralement de 1 à 3 éléments, étant commun pour qu'il n'en ait qu'un ou deux.

Que serait plus de performance, en gardant la concaténation ou en utilisant un StringBuilder?

StringBuilder bld = new StringBuilder()
foreach (MyObject o in myList)
  bld.Append(o.ToString());

Je ne sais pas si la création de StringBuilder prendra plus de temps que la concaténation standard dans le cas le plus courant.

C'est paresseux, les éléments de la liste ne changent pas une fois créés, donc l'identifiant est construit paresseusement une fois appelé.

En remarque ... Devrais-je utiliser un tableau fixe au lieu d'une liste? Aurais-je des performances ou une amélioration de la mémoire si je le fais? (La liste n'est utilisée que de toute façon comme un IEnumerable)

Une vue plus générale de la question pourrait être la suivante: combien de chaînes suffisent-elles pour arrêter la concaténation et commencer à construire?

Devrais-je même prendre la peine de tester le scénario?

if (myList.Count > 4) 
  ConcatWithStringBuilder(myList);
22
Jorge Córdoba

La réponse habituelle est que la concaténation de chaînes est plus efficace pour 4 à 8 chaînes. Cela dépend du blog que vous lisez.

N'écrivez pas de test pour décider de la méthode à utiliser. Si vous ne savez pas s'il dépassera la limite magique, utilisez simplement StringBuilder.

Exécutez ce code pour voir les résultats par vous-même:

const int sLen=30, Loops=5000;
DateTime sTime, eTime;
int i;
string sSource = new String('X', sLen);
string sDest = "";
// 
// Time string concatenation.
// 
sTime = DateTime.Now;
for(i=0;i<Loops;i++) sDest += sSource;
eTime = DateTime.Now;
Console.WriteLine("Concatenation took " + (eTime - sTime).TotalSeconds + " seconds.");
// 
// Time StringBuilder.
// 
sTime = DateTime.Now;
System.Text.StringBuilder sb = new System.Text.StringBuilder((int)(sLen * Loops * 1.1));
for(i=0;i<Loops;i++) sb.Append(sSource);
sDest = sb.ToString();
eTime = DateTime.Now;
Console.WriteLine("String Builder took " + (eTime - sTime).TotalSeconds + " seconds.");
// 
// Make the console window stay open
// so that you can see the results when running from the IDE.
// 
Console.WriteLine();
Console.Write("Press Enter to finish ... ");
Console.Read();

Réf. http://support.Microsoft.com/kb/306822

29
Daniel Robinson

Je soutiens l'idée de garder les choses simples jusqu'à ce que vous ayez une bonne raison de les rendre complexes.

Pour quelque chose comme 2 à 5 éléments, il ne sert à rien d'utiliser StringBuilder (à moins que vous ne répétiez cette concaténation de façon continue). La meilleure syntaxe lisible "+ =" a plus de valeur.

13
user151323

Une vue plus générale de la question pourrait être la suivante: combien de chaînes suffisent-elles pour arrêter la concaténation et commencer à construire?

Cela dépend de la longueur des chaînes et si vous pouvez prédire la longueur cible vous devez alors fournir la longueur au constructeur StringBuilderet vous devez les concaténer tous en même temps ou en plusieurs étapes.

Si vous les concaténer immédiatement (comme s = "A" + "b" + "c" + "d") utiliser StringBuilder n'aura probablement aucun sens.

Si vous pouvez prédire exactement la longueur, alors même pour 3 chaînes, StringBuilder sera plus rapide.

En général, StringBuilder est plus rapide si vous avez plus de 5 concats environ. Mais même dans ce cas, le simple fait de concaténer les chaînes a généralement peu de frais généraux (sauf s’il fonctionne dans une boucle serrée).

Dès que vous atteignez 10 concat, utiliser StringBuilder sera probablement favorable.

Edit: Juste pour que ce soit clair: dans votre cas, vous devriez clairement vous passer de StringBuilder.

4
Foxfire

Pourquoi ne pouvez-vous pas simplement utiliser

String.Concat(myList)

au lieu de réinventer la roue? Il est très performant et pourtant simple comme bonjour.
Plus d'infos ici: http://msdn.Microsoft.com/en-us/library/system.string.concat.aspx

4
Sarge Borsch

La concaténation de chaînes IMO est plus lisible. Vous utilisez + et + = au lieu de strBldInstance.Add () qui peut brouiller un peu le code, 

StringBuilder existe pour rendre la concaténation plus performante, beaucoup plus, mais je sacrifie généralement un peu de performance pour la lisibilité du code. Votre code ne sera pas affecté si vous chattez quelques chaînes ici et là. Et pour ce bloc de code qui traite souvent de nombreuses chaînes, utilisez StringBuilder.

2
Paul Sasik

Le constructeur de cordes sera probablement un peu plus rapide dans ce cas, mais en réalité, il ne sera probablement pas suffisant pour vous inquiéter. Cela va vraiment dépendre de deux choses, le nombre de fois que vous recréez la chaîne (parce que les chaînes sont immuables et que vous devez obligatoirement créer une nouvelle chaîne à partir des deux chaînes existantes), et la taille des éléments de chaîne que vous souhaitez créer. concaténent ensemble. La concaténation de cinq chaînes de 2 octets sera très différente de la concaténation de 5 chaînes de 5 000 octets chacune, car plus la chaîne est longue, plus le système doit faire beaucoup pour allouer de la mémoire et des objets de récupération de mémoire non plus utilisé. Le constructeur de cordes est un meilleur pari, car il a déjà été optimisé pour réunir des chaînes et vous n'avez pas à vous soucier de la performance.

En gardant tout cela à l’esprit, si vous savez à quel point la longueur finale de la chaîne sera grande, le constructeur de chaînes sera certainement plus rapide. Lorsque vous lui indiquez la quantité de mémoire à allouer pour la chaîne finale, il ne sera pas nécessaire de suivre le processus de réaffectation de mémoire.

0
kemiller2002

Si vous pouvez estimer le nombre d'octets qui seront utilisés pour la chaîne complète (et l'utiliser pour initialiser la capacité de StringBuilder), il est probable que StringBuilder surpasse la classe String lorsqu'il effectue plus d'environ 3 concat.

0
Lucero

J'utiliserais StringBuilder simplement parce que vous voulez être cohérent dans toute une application. L'instanciation d'un objet Java/.NET ne prend pas beaucoup de temps non plus, bien que je suppose qu'il y aurait un certain entretien lors de la configuration de StringBuilder. Ce n’est pas pire que la création de plusieurs objets String via la concaténation.

0
JeeBee

Si vous le pouviez, vous pourriez vous amuser et éliminer complètement la boucle for et utiliser l’agrégat?

var concatstring = mylist.Aggregate("", (acc, item) => acc + "." + item);

pas sûr sur les frais généraux de cela cependant?

0
Luke Duddridge

Vous avez trouvé ce sujet (performances) lors de la résolution d'un problème de code de conduite. Pour une chaîne de caractères> 42k (ou plus) , stringBuilder est plus rapide pour une raison quelconque.

Le code suivant pour inverser une chaîne a fonctionné dans le cas spécifié (> 42 000 caractères) avec StringBuilder.

public static string ReverseString(string s)
{
   var toReturn = new StringBuilder();
   for (var i = s.Length - 1; i >= 0; i--)
   {
      toReturn.Append(s[i]);
      }
   return toReturn.ToString();
}

mais la même fonction ne fonctionnait pas avec la concaténation de chaînes, c'est-à-dire toReturn + = s [i]

0
Aimal Khan