web-dev-qa-db-fra.com

String vs. StringBuilder

Je comprends la différence entre String et StringBuilder (StringBuilder étant mutable), mais existe-t-il une grande différence de performances entre les deux?

Le programme sur lequel je travaille a beaucoup de chaînes ajoutées à la casse (plus de 500). L'utilisation de StringBuilder est-elle un meilleur choix?

204
Kuvo

Oui, la différence de performance est significative. Voir l'article de la Base de connaissances " Comment améliorer les performances de concaténation de chaînes dans Visual C # ".

J'ai toujours essayé d'abord de coder par souci de clarté, puis d'optimiser les performances par la suite. C'est beaucoup plus facile que de faire l'inverse! Cependant, après avoir constaté l'énorme différence de performances de mes applications entre les deux, j'y réfléchis maintenant un peu plus attentivement.

Heureusement, il est relativement simple d'exécuter une analyse de performance sur votre code pour voir où vous passez le temps, puis de le modifier pour qu'il utilise StringBuilder si nécessaire.

225
Jay Bazuzi

Pour clarifier ce que Gillian a dit à propos de 4 cordes, si vous avez quelque chose comme ceci:

string a,b,c,d;
 a = b + c + d;

alors ce serait plus rapide en utilisant des chaînes et l'opérateur plus. En effet, (comme Java, comme le souligne Eric), il utilise automatiquement StringBuilder en interne (en fait, il utilise une primitive que StringBuilder utilise également).

Cependant, si ce que vous faites est plus proche de:

string a,b,c,d;
 a = a + b;
 a = a + c;
 a = a + d;

Ensuite, vous devez utiliser explicitement un StringBuilder. .Net ne crée pas automatiquement un StringBuilder ici, car ce serait inutile. À la fin de chaque ligne, "a" doit être une chaîne (immuable). Il doit donc créer et disposer d'un StringBuilder sur chaque ligne. Pour plus de rapidité, vous devez utiliser le même StringBuilder jusqu'à ce que vous ayez fini de construire:

string a,b,c,d;
StringBuilder e = new StringBuilder();
 e.Append(b);
 e.Append(c);
 e.Append(d);
 a = e.ToString();
54
James Curran

StringBuilder est préférable SI vous faites plusieurs boucles, ou des fourches dans votre passe de code ... cependant, pour des performances PURE, si vous pouvez vous en sortir avec un SINGLE = déclaration de chaîne, alors c'est beaucoup plus performant.

Par exemple:

string myString = "Some stuff" + var1 + " more stuff"
                  + var2 + " other stuff" .... etc... etc...;

est plus performant que

StringBuilder sb = new StringBuilder();
sb.Append("Some Stuff");
sb.Append(var1);
sb.Append(" more stuff");
sb.Append(var2);
sb.Append("other stuff");
// etc.. etc.. etc..

Dans ce cas, StringBuild peut être considéré comme plus facile à gérer, mais n'est pas plus performant que la déclaration à chaîne unique.

9 fois sur 10 cependant ... utilisez le constructeur de cordes.

Sur une note de côté: string + var est également plus performant que l'approche string.Format (généralement) qui utilise un StringBuilder en interne (en cas de doute ... vérifiez réflecteur!)

28
calebjenkins

Ce repère montre que la concaténation régulière est plus rapide lorsque vous combinez 3 chaînes ou moins.

http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/

StringBuilder peut améliorer considérablement l'utilisation de la mémoire, en particulier si vous ajoutez 500 chaînes ensemble.

Prenons l'exemple suivant:

string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
    buffer += i.ToString();
}
return buffer;

Qu'est-ce qui se passe dans la mémoire? Les chaînes suivantes sont créées:

1 - "The numbers are: "
2 - "0"
3 - "The numbers are: 0"
4 - "1"
5 - "The numbers are: 01"
6 - "2"
7 - "The numbers are: 012"
8 - "3"
9 - "The numbers are: 0123"
10 - "4"
11 - "The numbers are: 01234"
12 - "5"
13 - "The numbers are: 012345"

En ajoutant ces cinq nombres à la fin de la chaîne, nous avons créé 13 objets chaîne! Et 12 d'entre eux étaient inutiles! Hou la la!

StringBuilder résout ce problème. Ce n'est pas une "chaîne mutable" car nous entendons souvent ( toutes les chaînes dans .NET sont immuables ). Cela fonctionne en gardant un tampon interne, un tableau de caractères. L'appel de Append () ou AppendLine () ajoute la chaîne à l'espace vide à la fin du tableau de caractères; si le tableau est trop petit, il crée un nouveau tableau plus grand et y copie le tampon. Ainsi, dans l'exemple ci-dessus, StringBuilder peut ne nécessiter qu'un seul tableau contenant les 5 ajouts à la chaîne - en fonction de la taille de son tampon. Vous pouvez indiquer à StringBuilder quelle doit être la taille de sa mémoire tampon dans le constructeur.

23
Matt Trunnell

Un exemple simple pour démontrer la différence de vitesse lors de l’utilisation de la concaténation String vs StringBuilder:

System.Diagnostics.Stopwatch time = new Stopwatch();
string test = string.Empty;
time.Start();
for (int i = 0; i < 100000; i++)
{
    test += i;
}
time.Stop();
System.Console.WriteLine("Using String concatenation: " + time.ElapsedMilliseconds + " milliseconds");

Résultat:

Utilisation de la concaténation de chaînes: 15423 millisecondes

StringBuilder test1 = new StringBuilder();
time.Reset();
time.Start();
for (int i = 0; i < 100000; i++)
{
    test1.Append(i);
}
time.Stop();
System.Console.WriteLine("Using StringBuilder: " + time.ElapsedMilliseconds + " milliseconds");

Résultat:

Utilisation de StringBuilder: 10 millisecondes

En conséquence, la première itération a duré 15423 ms, tandis que la deuxième itération avec StringBuilder a pris 10 ms.

Il me semble que l'utilisation de StringBuilder est plus rapide, beaucoup plus rapide.

21
Diizzy

Oui, StringBuilder donne de meilleures performances lors d'opérations répétées sur une chaîne. C'est parce que toutes les modifications sont apportées à une seule instance, ce qui permet de gagner beaucoup de temps au lieu de créer une nouvelle instance telle que String.

String Vs Stringbuilder

  • String

    1. sous System espace de noms
    2. instance immuable (en lecture seule)
    3. la performance se dégrade en cas de changement continu de valeur
    4. fil sécuritaire
  • StringBuilder (chaîne mutable)

    1. sous System.Text espace de noms
    2. instance mutable
    3. affiche de meilleures performances puisque de nouvelles modifications sont apportées à l'instance existante

Nous recommandons vivement l'article de dotnet mob: String Vs StringBuilder en C # .

Question relative au dépassement de capacité de la pile: Mutabilité de chaîne lorsque la chaîne ne change pas en C #? .

12
Shamseer K

StringBuilder réduit le nombre d'allocations et d'assignations, au prix de la mémoire supplémentaire utilisée. Utilisé correctement, il peut supprimer complètement le besoin pour le compilateur d'allouer des chaînes de plus en plus grandes jusqu'à ce que le résultat soit trouvé.

string result = "";
for(int i = 0; i != N; ++i)
{
   result = result + i.ToString();   // allocates a new string, then assigns it to result, which gets repeated N times
}

vs.

String result;
StringBuilder sb = new StringBuilder(10000);   // create a buffer of 10k
for(int i = 0; i != N; ++i)
{
   sb.Append(i.ToString());          // fill the buffer, resizing if it overflows the buffer
}

result = sb.ToString();   // assigns once
8
moswald

String Vs String Builder:

La première chose à savoir est que dans quelle Assemblée vivent ces deux classes?

Alors,

string est présent dans System namespace.

et

StringBuilder est présent dans l'espace de nom System.Text.

Pour la déclaration string :

Vous devez inclure l'espace de noms System. quelque chose comme ça. Using System;

et

Pour StringBuilder déclaration:

Vous devez inclure l'espace de nom System.text. quelque chose comme ça. Using System.text;

Maintenant venez la la question réelle.

Quelle est la différence entre chaîne & StringBuilder ?

La principale différence entre les deux est que:

string est immuable.

et

StringBuilder est modifiable.

Alors maintenant, discutons de la différence entre immuable et mutable

Mutable: : signifie modifiable.

Immuable: : signifie non modifiable.

Par exemple:

using System;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // String Example

            string name = "Rehan";
            name = name + "Shah";
            name = name + "RS";
            name = name + "---";
            name = name + "I love to write programs.";

            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah RS --- I love to write programs."
        }
    }
}

Donc, dans ce cas, nous allons changer le même objet 5 fois.

Donc, la question évidente est que! Qu'est-ce qui se passe réellement sous le capot, lorsque nous changeons la même chaîne 5 fois.

C'est ce qui arrive quand nous changeons la même chaîne 5 fois.

laissez regarder la figure.

enter image description here

Explication:

Lorsque nous initialisons cette variable "name" à "Rehan", i-e string name = "Rehan", cette variable est créée sur une pile "name" et pointe vers cette valeur "Rehan". après que cette ligne soit exécutée: "nom = nom +" Shah ", la variable de référence ne pointe plus vers cet objet" Rehan "mais sur" Shah "et ainsi de suite.

Donc, string est immuable, ce qui signifie qu'une fois que nous avons créé l'objet dans la mémoire, nous ne pouvons plus le changer.

Ainsi, lorsque nous concaténons la variable name, l'objet précédent reste là dans la mémoire et un autre nouvel objet chaîne est créé ...

Donc, de la figure ci-dessus, nous avons cinq objets, les quatre objets sont jetés, ils ne sont pas utilisés du tout. Ils restent en mémoire et occupent la quantité de mémoire. "Garbage Collector" est responsable de ce nettoyage des ressources de la mémoire.

Donc, en cas de chaîne à tout moment, lorsque nous manipulons la chaîne encore et encore, nous avons plusieurs objets créés et restés dans la mémoire.

C'est donc l'histoire de la chaîne Variable.

Regardons maintenant vers l'objet StringBuilder. Par exemple:

using System;
using System.Text;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // StringBuilder Example

            StringBuilder name = new StringBuilder();
            name.Append("Rehan");
            name.Append("Shah");
            name.Append("RS");
            name.Append("---");
            name.Append("I love to write programs.");


            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah Rs --- I love to write programs."
        }
    }
}

Donc, dans ce cas, nous allons changer le même objet 5 fois.

Donc, la question évidente est que! Que se passe-t-il réellement sous le capot lorsque nous modifions le même StringBuilder 5 fois.

C'est ce qui arrive lorsque nous modifions le même StringBuilder 5 fois.

laissez regarder la figure. enter image description here

Explication: Dans le cas d'un objet StringBuilder. vous n'obtiendrez pas le nouvel objet. Le même objet sera modifié en mémoire, donc même si vous le modifiez et dites 10 000 fois, nous n’aurons toujours qu’un seul objet stringBuilder.

Vous n'avez pas beaucoup d'objets garbage ou d'objets stringBuilder non référencés, car ils peuvent être modifiés. Est-ce que mutable signifie que cela change avec le temps?

Différences:

  • String est présent dans l'espace de noms système, où Stringbuilder est présent dans l'espace de noms System.Text.
  • string est immuable là où StringBuilder est mutabe.
7
Rehan Shah

Les performances d'une opération de concaténation pour un objet String ou StringBuilder dépendent de la fréquence d'allocation de mémoire. Une opération de concaténation de chaînes alloue toujours de la mémoire, tandis qu'une opération de concaténation de StringBuilder n'alloue de la mémoire que si le tampon d'objet de StringBuilder est trop petit pour accueillir les nouvelles données. Par conséquent, la classe String est préférable pour une opération de concaténation si un nombre fixe d'objets String sont concaténés. Dans ce cas, les opérations de concaténation individuelles peuvent même être combinées en une seule opération par le compilateur. Un objet StringBuilder est préférable pour une opération de concaténation si un nombre arbitraire de chaînes sont concaténées. Par exemple, si une boucle concatène un nombre aléatoire de chaînes d'entrées utilisateur.

Source: MSDN

4
user487069

StringBuilder est préférable pour construire une chaîne à partir de nombreuses valeurs non constantes.

Si vous créez une chaîne à partir de nombreuses valeurs constantes, telles que plusieurs lignes de valeurs dans un document HTML ou XML ou d'autres morceaux de texte, vous pouvez vous en tirer en ajoutant simplement à la même chaîne, car presque tous les compilateurs le font. "pliage constant", un processus de réduction de l'arbre d'analyse lorsque vous avez beaucoup de manipulations constantes (il est également utilisé lorsque vous écrivez quelque chose comme int minutesPerYear = 24 * 365 * 60). Et pour les cas simples avec des valeurs non constantes ajoutées les unes aux autres, le compilateur .NET réduira votre code à quelque chose de similaire à ce que fait StringBuilder.

Mais lorsque votre ajout ne peut pas être réduit à quelque chose de plus simple par le compilateur, vous aurez besoin d'un StringBuilder. Comme le souligne le fizch, c'est plus susceptible de se produire à l'intérieur d'une boucle.

3
JasonTrue
2
Jim G.

L'utilisation de chaînes pour la concaténation peut entraîner une complexité d'exécution de l'ordre de O(n^2).

Si vous utilisez un StringBuilder, il y aura beaucoup moins de copie de mémoire à faire. Avec StringBuilder(int capacity), vous pouvez augmenter les performances si vous pouvez estimer la taille de la variable String finale. Même si vous n'êtes pas précis, vous devrez probablement augmenter la capacité de StringBuilder plusieurs fois, ce qui peut également améliorer les performances.

2
Steve g

J'ai constaté des gains de performances significatifs en utilisant l'appel de méthode EnsureCapacity(int capacity) sur une instance de StringBuilder avant de l'utiliser pour le stockage de chaînes. J'appelle généralement cela sur la ligne de code après l'instanciation. Cela a le même effet que si vous instanciez la StringBuilder comme ceci:

var sb = new StringBuilder(int capacity);

Cet appel alloue à l’avance la mémoire nécessaire, ce qui entraîne moins d’allocations de mémoire au cours de plusieurs opérations Append(). Vous devez vous faire une idée précise de la quantité de mémoire dont vous aurez besoin, mais pour la plupart des applications, cela ne devrait pas être trop difficile. Je me trompe généralement un peu trop de mémoire (nous parlons environ 1k).

2
Jason Jackson

Je pense que StringBuilder est plus rapide si vous avez plus de 4 chaînes à additionner. De plus, il peut faire des choses intéressantes comme AppendLine.

2
Gilligan

En .NET, StringBuilder est toujours plus rapide que l'ajout de chaînes. Je suis presque sûr qu'en Java, ils créent simplement un StringBuffer sous le capot lorsque vous ajoutez des chaînes, il n'y a donc pas vraiment de différence. Je ne sais pas pourquoi ils ne l'ont pas encore fait dans .NET.

2
Eric Z Beard

String et StringBuilder sont en réalité immuables. StringBuilder dispose de tampons intégrés qui permettent une gestion plus efficace de sa taille. Lorsque StringBuilder doit être redimensionné, il est réaffecté sur le tas. Par défaut, il est composé de 16 caractères. Vous pouvez le définir dans le constructeur.

par exemple.

StringBuilder sb = new StringBuilder (50);

1
capgpilk

En plus des réponses précédentes, la première chose que je fais toujours lorsque je pense à de tels problèmes est de créer une petite application de test. Dans cette application, effectuez un test de synchronisation pour les deux scénarios et voyez par vous-même ce qui est plus rapide.

IMHO, l'ajout de plus de 500 entrées de chaînes devrait absolument utiliser StringBuilder.

1
RichS

La concaténation de chaînes vous coûtera plus cher. En Java, vous pouvez utiliser StringBuffer ou StringBuilder en fonction de vos besoins. Si vous souhaitez une implémentation sécurisée avec un thread synchronisé, optez pour StringBuffer. Ce sera plus rapide que la concaténation de chaîne.

Si vous n'avez pas besoin d'une implémentation synchronisée ou sécurisée pour les threads, optez pour StringBuilder. Ce sera plus rapide que la concaténation de chaînes et plus rapide que StringBuffer, car il n’ya pas de surcharge de synchronisation.

1
raffimd

StringBuilder est nettement plus efficace, mais vous ne verrez pas cette performance à moins de faire beaucoup de modifications de chaînes.

Ci-dessous se trouve un morceau de code rapide pour donner un exemple de la performance. Comme vous pouvez le constater, les performances ne commencent vraiment à augmenter que lorsque vous vous lancez dans de grandes itérations.

Comme vous pouvez le constater, les 200 000 itérations ont pris 22 secondes, tandis que les 1 million d'itérations utilisant la variable StringBuilder étaient presque instantanées.

string s = string.Empty;
StringBuilder sb = new StringBuilder();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 50000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 200000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();
Console.WriteLine("Beginning Sb append at " + DateTime.Now.ToString());

for (int i = 0; i <= 1000000; i++)
{
    sb.Append("A");
}
Console.WriteLine("Finished Sb append at " + DateTime.Now.ToString());

Console.ReadLine();

Résultat du code ci-dessus:

Début de chaîne + au 28/01/2013 16:55:40.

Chaîne terminée + au 28/01/2013 16:55:40.

Début de chaîne + au 28/01/2013 16:55:40.

Terminé String + au 28/01/2013 16:56:02.

Début Sb append à 28/01/2013 16:56:02.

Terminé Sb append au 28/01/2013 16:56:02.

0
CathalMF

En règle générale, si je dois définir la valeur de la chaîne plus d'une fois, ou s'il y a des ajouts à la chaîne, il doit alors s'agir d'un constructeur de chaînes. J'ai vu des applications que j'avais écrites dans le passé avant d'apprendre sur les constructeurs de cordes qui ont une énorme empreinte de mémoire qui semble juste continuer à grandir. Changer ces programmes pour utiliser le constructeur de chaînes réduisait considérablement l'utilisation de la mémoire. Maintenant, je ne jure que par le constructeur de cordes.

0
user13288

Mon approche a toujours été d'utiliser StringBuilder lors de la concaténation de 4 chaînes ou plus OR Lorsque je ne sais pas comment une concaténation peut avoir lieu.

Article sur les bonnes performances ici

0
JohnC

StringBuilder est probablement préférable. La raison en est qu’elle alloue plus d’espace que nécessaire (vous définissez le nombre de caractères) pour laisser de la place pour les ajouts futurs. Ensuite, ces ajouts futurs qui entrent dans la mémoire tampon actuelle ne nécessitent aucune allocation de mémoire ni aucune récupération de place, ce qui peut coûter cher. En général, j'utilise StringBuilder pour la concatentation de chaînes complexes ou la mise en forme multiple, puis je convertis en chaîne normale lorsque les données sont complètes et je souhaite à nouveau obtenir un objet immuable.

0
deemer

Si vous faites beaucoup de concaténation de chaînes, utilisez un StringBuilder. Lorsque vous concaténez avec une chaîne, vous créez une nouvelle chaîne à chaque fois, en utilisant davantage de mémoire.

Alex

0
Alex Fort