32 votes

"N'utilisez pas StringBuilder ou foreach dans ce chemin de code chaud"

Je suis de la navigation sur le code source de l'Open Source SignalR projet, et je vois cette diff de code qui a le droit "de Ne pas utiliser StringBuilder ou foreach dans cette chaude chemin de code" :

-           public static string MakeCursor(IEnumerable<Cursor> cursors)
+           public static string MakeCursor(IList<Cursor> cursors)
            { 
-               var sb = new StringBuilder();
-               bool first = true;
-               foreach (var c in cursors)
+               var result = "";
+               for (int i = 0; i < cursors.Count; i++)
                {
-                   if (!first)
+                   if (i > 0)
                    {
-                       sb.Append('|');
+                       result += '|';
                    }
-                   sb.Append(Escape(c.Key));
-                   sb.Append(',');
-                   sb.Append(c.Id);
-                   first = false;
+                   result += Escape(cursors[i].Key);
+                   result += ',';
+                   result += cursors[i].Id;
                }
-               return sb.ToString();
+               return result;
            }

Je comprends pourquoi foreach pourrait être moins efficace parfois, et pourquoi il est remplacé par pour.

Cependant, j'ai appris et expérimenté que le StringBuilder est le moyen le plus efficace pour concaténer des chaînes. Donc, je me demande pourquoi l'auteur a décidé de le remplacer à la norme de concaténation.

Quel est le problème ici, et en général sur l'utilisation de StringBuilder ?

30voto

dfowler Points 16530

J'ai fait le changement de code et oui il a fait une énorme différence dans le nombre d'allocations (GetEnumerator()) appels vs pas. Imaginez ce code est des millions de fois par seconde. Le nombre d'agents recenseurs alloué est ridicule et peut être évité.

edit: Nous avons maintenant inverser le contrôle afin d'éviter toute allocations (écrit à l'auteur directement): https://github.com/SignalR/SignalR/blob/2.0.2/src/Microsoft.AspNet.SignalR.Core/Messaging/Cursor.cs#L36

3voto

IvoTops Points 2097

Espérons que le gars qui a changé cela a réellement mesuré la différence.

  • L'instanciation d'un nouveau constructeur de chaînes à chaque fois est fastidieuse. Cela met également la pression sur la mémoire / la récupération de place.
  • Le compilateur peut générer du code 'stringbuilderlike' pour des concaténations simples
  • Le FOR peut en réalité être plus lent car il peut nécessiter une vérification des limites qui n'est pas effectuée avec des boucles foreach car les compilateurs "savent" qu'elles sont dans les limites.

2voto

larsm Points 5337

Il dépend du nombre d' Cursors fourni à la fonction.

La plupart des comparaisons entre les deux apporaches semble favoriser StringBuilder - dessus de la chaîne de concatination quand concatinating de 4 à 10 cordes. J'seraient le plus susceptibles de favoriser StringBuilder si je n'avais pas explicite les raisons de ne pas trop (par exemple, comparaison des performances des deux approches pour mon problème/demande). Je considère pré-allouer un tampon dans l' StringBuilder pour éviter les (nombreux) de réaffectations.

Voir la concaténation de Chaîne vs Générateur de Chaîne. La Performance et la Concaténation avec StringBuilders contre les Cordes pour une discussion sur le sujet.

1voto

Dave Doknjas Points 2626

Combien de concaténations faites-vous? Si nombreux, utilisez StringBuilder. Si seulement quelques-uns, la surcharge de la création de StringBuilder l'emportera sur tout avantage.

1voto

Blam Points 17325

Je vais mettre mon argent

            StringBuilder sb = new StringBuilder();
           bool first = true;
           foreach (Cursor c in cursors)
           {
                if (first)
                {
                   first = false;  // only assign it once
                }
                else
                {
                    sb.Append('|');
                }
                sb.Append(Escape(c.Key) + ',' + c.Id);
            }
            return sb.ToString();
 

Mais je mettrais mon argent et la mise à jour de Dfowler. Découvrez le lien dans sa réponse.

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