Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

CoqBlog

.NET is good :-)
{ Blog de coq }

Actualités

Un bon moyen de se souvenir de l'ami StringBuilder !

Si vous avez du mal à vous souvenir / à faire comprendre qu'il ne faut pas utiliser de concaténation de chaîne de caractères à partir du moment où :

  • le nombre de chaînes n'est pas déterminé
  • les chaînes ne sont pas littérales (car dans ce cas, la concaténation est effectuée à la compilation)
  • l'opération ne se fait pas en une seule fois (donc, pas de concaténation dans des boucles)


Voici peut être un moyen de vous en souvenir plus facilement : écrivez donc la phrase suivante sur du papier, à l'ancienne : "Je ne dois pas utiliser la concaténation dans une boucle !"

Mais vous allez le faire façon concaténation de chaîne de caractères en .NET (et Java d'ailleurs, si je ne m'abuse) !
Pour celà, vous aller l'écrire mot après mot. Naturellement me direz vous.
Nous allons considérer les espaces et la ponctuation comme faisant partie du mot précédent, ce qui fait que la phrase citée comportera donc 10 "mots".
Voici la marche à suivre : 

  1. prendre une feuille, écrire "Je "
  2. prendre une autre feuille, écrire "Je ne ", jeter la feuille précédente
  3. prendre une autre feuille, écrire "Je ne dois ", jeter la feuille précédente
  4. prendre une autre feuille, écrire "Je ne dois pas ", jeter la feuille précédente
  5. prendre une autre feuille, écrire "Je ne dois pas utiliser ", jeter la feuille précédente
  6. prendre une autre feuille, écrire "Je ne dois pas utiliser la ", jeter la feuille précédente
  7. prendre une autre feuille, écrire "Je ne dois pas utiliser la concaténation ", jeter la feuille précédente
  8. prendre une autre feuille, écrire "Je ne dois pas utiliser la concaténation dans ", jeter la feuille précédente
  9. prendre une autre feuille, écrire "Je ne dois pas utiliser la concaténation dans une ", jeter la feuille précédente
  10. prendre une autre feuille, écrire "Je ne dois pas utiliser la concaténation dans une boucle !", jeter la feuille précédente

 

Bilan des opérations pour votre phrase de 10 mots :

  • vous avez gaspiller 9 feuilles
  • vous avez écrit 45 mots de plus que nécessaire

Pour une phrase de 11 mots ça aurait donner :

  • un gaspillage de 10 feuilles
  • écriture de 55 mots de plus que nécessaire

Ca fait mal, non ? Vous savez maintenant ce que ressent votre ami le CLR et son camarade le Garbage Collector.

Voilà, ça devrait aider à retenir la signification du caractère immuable de la classe String ;-)

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: samedi 28 juillet 2007 11:43 par coq
Classé sous :

Commentaires

badrbadr a dit :

Excellent moyen pédagogique :D

# juillet 28, 2007 11:59

Danuz a dit :

LOL ! Bonne leçon ! :D

# juillet 28, 2007 12:16

pc152 a dit :

Que du bon, vraiment super cette leçon. j'avais du mal à expliquer à mes développeurs le pourquoi du comment, maintenant ils vont utiliser des feuilles de papier ;)

Merci

# juillet 28, 2007 12:19

Miiitch a dit :

FxCop peut aussi être un bon moyen de faire apprendre cette règle :)

# juillet 28, 2007 12:46

coq a dit :

Yep, mais ce que je cherche surtout c'est d'éviter que cette règle de FxCop serve :-D (non pas que je ne l'aime pas hein ^^)

PS : pensez aux arbres quand même hein ! :p

# juillet 28, 2007 12:56

FREMYCOMPANY a dit :

Ouais mais bon, si c'est juste pour faire un Analyse(" " & Text & " "), je vais quand même pas me casser la tête à créer un StringBuilder...

Parce que dans ce cas, je vais me taper

Dim SB as new System.Text.StringBuilder()

SB.append(" ") : SB.append(Text) : SB.append(" ")

Analyse(SB.toString()) : SB = Nothing

Mais je me pose une question : En Java, j'ai lu que le compilateur "corrigeait" automatiquement cette "faute", soit si j'écris " " + Text + " ", il va faire un StringBuilder et y appender les trois, DotNet ne ferait-il pas cela aussi ?

Sinon reste un Module avec Public Function S(ParamArray Items as String) as String qui se chargerait de la concaténation via StringBuilder dans ce genre de cas... Alors on aurait plus que Analyse(S(" ", Text, " ")), ce qui n'est pas encore trop lourd

# juillet 28, 2007 13:05

coq a dit :

" " + Text + " " entre dans le cadre des opérations au nombre de chaines connu et réalisé en une seule fois, pour lesquels l'utilisation de StringBuilder n'apporte pas de réel intérêt, et causerais même peut être une perte de performance, sans parler de la neutralisation de certaines optimisations du compilateur.

J'aurais quand même tendance à préférer une solution basée sur une chaîne formatée, avec String.Format, pour la lisibilité du code en lui même.

Mais ça doit être un peu moins rapide que la forme " " + Text + " " pour laquelle le compilateur va utiliser String.Concat(params String[]), ou plutot String.Concat(String, String, String) dans le cas présent.

Pour le comportement du compilateur Java je ne sais pas, un dev Java peut confirmer ?

Mais ça me paraitrais quand même bizarre de basculer automatiquement sur du StringBuilder (ou autre) en dehors d'une boucle.

# juillet 28, 2007 14:10

sebmafate a dit :

j'adore l'exemple... voici un bon moyen pédagogique !

# juillet 28, 2007 14:43

ROMELARD Fabrice a dit :

Je vais vous balancer à Nicolas Hulot moi ;)

Excellent en tous cas

Fabrice

# juillet 28, 2007 16:28

FREMYCOMPANY a dit :

Lol, si vous avez un grand nombre de programmeur à raisonner, optez plutout pour le postit, c'est plus petit qu'une feuille mais la phrase y tiendra en entier ;)

# juillet 28, 2007 16:32

Yxion a dit :

J'utilise pas mal les StringBuilder... mais apparement pas assez... merci, moi qui essais de raisonner sur le gaspillage pollueur lol.

# juillet 28, 2007 16:44

gpommier a dit :

en effet, excellent !

# juillet 28, 2007 16:51

cyril a dit :

mdr l'exemple :-)

Pour ma part j'utilise un stringbuilder à partir de 20 concaténations, car la création d'un stringbuilder est couteux. Il m'arrive donc de faire des += dans des boucles quand je sais qu'il n'y aura pas plus de 15/20 concaténations ...

Par contre, contrairement à ce qui est dit String.Concat est plus rapide que le +

# juillet 28, 2007 19:21

Lutinore a dit :

En voyant le titre je me suis dit "tiens ça doit être un post sur le blog de Coq ça.." :p

# juillet 28, 2007 20:31

coq a dit :

Je parlais de String.Format hein, pas de String.Concat qui sera de toute façon utilisée à la concaténation avec +
C'est vrai que le formatage du commentaire laisse à désirer -_-

Concernant le "faible" volume de concaténations, je ne suis pas certain que le gain de la non création d'une instance de StringBuilder soit suffisant pour combler celui la perte due aux allocations successives de chaînes de caractères.
Il faudrait tester en situation réelle, mais un petit test bateau avec CLRProfiler donnera déjà quelques indications de la différence qu'il peut y avoir :
10 concaténations de "test" (octets alloués durant le traitement) :
- Concat : 700
- StringBuilder : 298
20 concaténations de "test" (octets alloués durant le traitement) :
- Concat : 2200
- StringBuilder : 572

Dans un contexte web, la différence peut faire mal.
Après il y a aussi le problème lié à la taille des chaînes : si jamais elles dépassent la limite des 85000 octets, elles sont alloués sur le heap dédié aux objets larges, qui a la particularité de ne pas être compacté.
Bref, il faut faire les tests en situation réelle ^^

 

# juillet 28, 2007 21:01

cyril a dit :

Au niveau de la mémoire consommées je connais pas les différence entre le concat et les stringbuilder mais stringbuilder devrais mieux s'en sortir. La mémoire sur des petites string n'est pas important, quelle différence entre 700 octets et 300 octets quand on a bien souvent plus d'1 000 000 000 d'octets :p

Dans bien des cas on peut aussi utiliser un stream plutot qu'un string, ce qui améliore souvent les perfs ...

je viens de faire un test au niveau des temps de réponses :

       static void Main(string[] args)

       {

           int[] c = new int[] { 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000 };

           Stopwatch watcher = new Stopwatch();

           Console.WriteLine();

           Console.WriteLine("Test avec concatenation");

           for (int i = 0; i < c.Length; i++)

           {

               watcher.Reset();

               watcher.Start();

               String s = String.Empty;

               for (int j = 0; j < cIdea; j++)

               {

                   s += "test";

               }

               watcher.Stop();

               Console.WriteLine(String.Format("{0}\t\t{1} ticks", cIdea, watcher.ElapsedTicks));

           }

           Console.WriteLine();

           Console.WriteLine("Test avec String.Concat");

           for (int i = 0; i < c.Length; i++)

           {

               watcher.Reset();

               watcher.Start();

               String s = String.Empty;

               for (int j = 0; j < cIdea; j++)

               {

                   s = String.Concat(s, "test");

               }

               watcher.Stop();

               Console.WriteLine(String.Format("{0}\t\t{1} ticks", cIdea, watcher.ElapsedTicks));

           }

           Console.WriteLine();

           Console.WriteLine("Test avec StringBuilder");

           for (int i = 0; i < c.Length; i++)

           {

               watcher.Reset();

               watcher.Start();

               StringBuilder sb = new StringBuilder();

               for (int j = 0; j < cIdea; j++)

               {

                   sb.Append("test");

               }

               sb.ToString();

               watcher.Stop();

               Console.WriteLine(String.Format("{0}\t\t{1} ticks", cIdea, watcher.ElapsedTicks));

           }

           Console.ReadLine();

       }

Test avec concatenation

5               11 ticks

10              11 ticks

20              13 ticks

50              75 ticks

100             220 ticks

200             865 ticks

500             4751 ticks

1000            28393 ticks

2000            72152 ticks

5000            389018 ticks

10000           1290447 ticks

20000           8672803 ticks

50000           61940775 ticks

Test avec String.Concat

5               10 ticks

10              10 ticks

20              13 ticks

50              45 ticks

100             133 ticks

200             383 ticks

500             4947 ticks

1000            45621 ticks

2000            153517 ticks

5000            611332 ticks

10000           2008615 ticks

20000           8142212 ticks

50000           55033635 ticks

Test avec StringBuilder

5               20 ticks

10              13 ticks

20              13 ticks

50              17 ticks

100             26 ticks

200             67 ticks

500             100 ticks

1000            187 ticks

2000            357 ticks

5000            984 ticks

10000           2254 ticks

20000           8650 ticks

50000           16131 ticks

# juillet 28, 2007 23:48

coq a dit :

Le temps qui sera consommé pour la libération des 400 supplémentaires ;-)

Pour le stream c'est exact, ce qui permet de toute façon de garder un code unique quel que soit le type de sortie désiré, nous fournir une chaine est la raison de vivre de StringWriter (et de son ami StringBuilder interne ^^)

# juillet 29, 2007 00:27

coq a dit :

Voir aussi le post de Cyril concernant le problème similaire en JavaScript :

StringBuilder en JavaScript : concatenation de String : http://blogs.codes-sources.com/cyril/archive/2008/02/17/stringbuilder-en-javascript-concatenation-de-string.aspx

# février 17, 2008 11:54
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01