Essayez ce code.
C'est une version légèrement modifiée de votre code.
1. J'ai supprimé Console.WriteLine car il est probablement quelques ordres de grandeur plus lent que ce que j'essaie de mesurer.
2. Je démarre le chronomètre avant la boucle et je l'arrête juste après, de cette façon je ne perds pas de précision si la fonction prend par exemple 26,4 ticks pour s'exécuter.
3. La façon dont vous avez divisé le résultat par quelques itérations était erronée. Voyez ce qui se passe si vous avez 1000 millisecondes et 100 millisecondes. Dans les deux cas, vous obtiendrez 0 ms après l'avoir divisé par 1000000.
Stopwatch s = new Stopwatch();
var p = new { FirstName = "Bill", LastName = "Gates" };
int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;
string result;
s.Start();
for (var i = 0; i < n; i++)
result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();
Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);
Voici mes résultats:
1000000 x résultat = string.Format ("{0} {1}", p.FirstName, p.LastName); pris: 618ms - 2213706 ticks
1000000 x résultat = (p.Prénom + "" + p.LastName); a pris: 166ms - 595610 tiques
Michał Piaskowski
la source
string.Format
qui n'utilise aucune fonctionnalité de formatage composite (c'est-à-dire simplement simple{0}
) et les remplace par la concaténation de chaînes considérablement plus rapide. Je me demande qu'un tel exploit est réalisable avec un réécriveur IL existant tel que PostSharp.Je suis étonné que tant de gens veuillent immédiatement trouver le code qui s'exécute le plus rapidement. Si UN MILLION d'itérations prennent ENCORE moins d'une seconde à traiter, cela sera-t-il perceptible de quelque manière que ce soit pour l'utilisateur final? Probablement pas.
J'irais avec l'
String.Format
option, uniquement parce que cela a le plus de sens d'un point de vue architectural. Je me fiche de la performance jusqu'à ce que cela devienne un problème (et si c'était le cas, je me demanderais: Dois-je concaténer un million de noms à la fois? Ils ne rentreront certainement pas tous à l'écran ...)Considérez si votre client souhaite le modifier ultérieurement afin qu'il puisse configurer l'affichage
"Firstname Lastname"
ou"Lastname, Firstname."
l'option Avec l'option Format, c'est facile - il suffit de remplacer la chaîne de format. Avec le concat, vous aurez besoin de code supplémentaire. Bien sûr, cela ne semble pas grave dans cet exemple particulier, mais extrapolez.la source
Oh mon Dieu - après avoir lu l'une des autres réponses, j'ai essayé d'inverser l'ordre des opérations - alors effectuez d'abord la concaténation, puis le String.Format ...
Ainsi l'ordre des opérations fait une ENORME différence, ou plutôt la toute première opération est TOUJOURS beaucoup plus lente.
Voici les résultats d'une exécution où les opérations sont effectuées plusieurs fois. J'ai essayé de changer les commandes mais les choses suivent généralement les mêmes règles, une fois que le premier résultat est ignoré:
Comme vous pouvez le voir, les exécutions ultérieures de la même méthode (j'ai refactoré le code en 3 méthodes) sont progressivement plus rapides. La méthode la plus rapide semble être la méthode Console.WriteLine (String.Concat (...)), suivie de la concaténation normale, puis des opérations formatées.
Le délai initial de démarrage est probablement l'initialisation de Console Stream, car placer une Console.Writeline ("Start!") Avant la première opération ramène tous les temps en ligne.
la source
Les chaînes sont immuables, cela signifie que le même petit morceau de mémoire est utilisé à plusieurs reprises dans votre code. Ajouter les deux mêmes chaînes ensemble et créer la même nouvelle chaîne encore et encore n'a pas d'impact sur la mémoire. .Net est suffisamment intelligent pour utiliser la même référence mémoire. Par conséquent, votre code ne teste pas vraiment la différence entre les deux méthodes concat.
Essayez ceci pour la taille:
Exemple de sortie:
la source
string.Format
vaut le petit coup de performance ici. Sur le plan architectural, c'est mieux car cela signifie que vous pouvez modifier le format plus facilement. Mais je ne vois vraiment pas l'intérêt de stringbuilder. Tous les autres threads ici indiquent que vous devez utiliser Stringbuilder au lieu de concaténer des chaînes. Quel est l'avantage? Clairement pas de vitesse, comme le prouve cette référence.Pitié les pauvres traducteurs
Si vous savez que votre application restera en anglais, alors très bien, enregistrez les tics d'horloge. Cependant, de nombreuses cultures voient généralement Lastname Firstname dans, par exemple, les adresses.
Alors utilisez
string.Format()
, surtout si vous allez un jour avoir votre application partout où l'anglais n'est pas la première langue.la source
string.Format()
comporterait-il différemment selon les cultures? N'afficherait-il pas toujours le prénom puis le nom de famille? Il semble que vous deviez prendre en compte la culture différente dans les deux situations. J'ai l'impression de manquer quelque chose ici.string.Format()
sauriez-vous que vous utilisiez un nom pour une adresse? S'il étaitstring.Format()
échangé en{0} {1}
fonction de la culture, je le considérerais comme cassé.Voici mes résultats sur 100 000 itérations:
Et voici le code de banc:
Donc, je ne sais pas quelle réponse marquer comme réponse :)
la source
La concaténation de chaînes est bien dans un scénario simple comme celui-ci - c'est plus compliqué avec quelque chose de plus compliqué que cela, même LastName, FirstName. Avec le format, vous pouvez voir, en un coup d'œil, quelle sera la structure finale de la chaîne lors de la lecture du code, avec la concaténation, il devient presque impossible de discerner immédiatement le résultat final (sauf avec un exemple très simple comme celui-ci).
Ce que cela signifie à long terme, c'est que lorsque vous reviendrez pour modifier le format de votre chaîne, vous pourrez soit entrer et faire quelques ajustements à la chaîne de format, soit plisser votre front et commencer à vous déplacer. types d’accesseurs de propriété mélangés à du texte, ce qui est plus susceptible d’introduire des problèmes.
Si vous utilisez .NET 3.5, vous pouvez utiliser une méthode d'extension comme celle-ci et obtenir une syntaxe simple et rapide comme celle-ci:
Enfin, à mesure que votre application devient de plus en plus complexe, vous pouvez décider que pour gérer correctement les chaînes de votre application, vous souhaitez les déplacer dans un fichier de ressources à localiser ou simplement dans un assistant statique. Ce sera BEAUCOUP plus facile à réaliser si vous avez toujours utilisé des formats, et votre code peut être tout simplement refacturé pour utiliser quelque chose comme
la source
Pour une manipulation très simple, j'utiliserais la concaténation, mais une fois que vous avez dépassé 2 ou 3 éléments, le format devient plus approprié à l'OMI.
Une autre raison de préférer String.Format est que les chaînes .NET sont immuables et que cela crée moins de copies temporaires / intermédiaires.
la source
Bien que je comprenne parfaitement la préférence de style et que j'ai choisi la concaténation pour ma première réponse en partie en fonction de ma propre préférence, une partie de ma décision était basée sur l'idée que la concaténation serait plus rapide. Donc, par curiosité, je l'ai testé et les résultats ont été stupéfiants, surtout pour une si petite corde.
En utilisant le code suivant:
J'ai obtenu les résultats suivants:
L'utilisation de la méthode de formatage est plus de 100 fois plus lente !! La concaténation ne s'est même pas enregistrée à 1 ms, c'est pourquoi j'ai également sorti les graduations de la minuterie.
la source
À partir de C # 6.0, des chaînes interpolées peuvent être utilisées pour ce faire, ce qui simplifie encore plus le format.
Les chaînes interpolées ont des performances similaires à String.Format, mais une meilleure lisibilité et une syntaxe plus courte, en raison du fait que les valeurs et les expressions sont insérées en ligne.
Veuillez également vous référer à cet article dotnetperls sur l'interpolation de chaîne.
Si vous recherchez un moyen par défaut de formater vos chaînes, cela a du sens en termes de lisibilité et de performances (sauf si les microsecondes vont faire une différence dans votre cas d'utilisation spécifique).
la source
Pour la concaténation de chaînes de base, j'utilise généralement le second style - plus facile à lire et plus simple. Cependant, si je fais une combinaison de chaînes plus compliquée, j'opte généralement pour String.Format.
String.Format enregistre de nombreux guillemets et plus ...
Seuls quelques charicteurs ont été enregistrés, mais je pense que, dans cet exemple, le format le rend beaucoup plus propre.
la source
Un meilleur test serait de surveiller votre mémoire en utilisant Perfmon et les compteurs de mémoire CLR. Je crois comprendre que la raison pour laquelle vous souhaitez utiliser String.Format au lieu de simplement concaténer des chaînes est que, puisque les chaînes sont immuables, vous chargez inutilement le ramasse-miettes avec des chaînes temporaires qui doivent être récupérées lors de la prochaine passe.
StringBuilder et String.Format, bien que potentiellement plus lents, sont plus efficaces en mémoire.
Qu'y a-t-il de si mauvais dans la concaténation de chaînes?
la source
En général, je préfère le premier, car surtout lorsque les cordes deviennent longues, cela peut être beaucoup plus facile à lire.
L'autre avantage est, je crois, celui des performances, car ce dernier exécute en fait 2 instructions de création de chaîne avant de passer la chaîne finale à la méthode Console.Write. String.Format utilise un StringBuilder sous les couvertures, je crois, donc les concaténations multiples sont évitées.
Il convient cependant de noter que si les paramètres que vous passez à String.Format (et d'autres méthodes telles que Console.Write) sont des types de valeur, ils seront encadrés avant d'être transmis, ce qui peut fournir ses propres performances. Article de blog à ce sujet ici .
la source
Dans une semaine le 19 août 2015, cette question aura exactement sept (7) ans. Il existe maintenant une meilleure façon de procéder. Mieux en termes de maintenabilité car je n'ai fait aucun test de performance par rapport à la simple concaténation de chaînes (mais est-ce important de nos jours? Quelques millisecondes de différence?). La nouvelle façon de le faire avec C # 6.0 :
Cette nouvelle fonctionnalité est meilleure , IMO, et en fait meilleure dans notre cas car nous avons des codes où nous construisons des chaînes de requêtes dont les valeurs dépendent de certains facteurs. Imaginez une chaîne de requêtes où nous avons 6 arguments. Donc au lieu de faire un, par exemple:
in peut être écrit comme ceci et c'est plus facile à lire:
la source
la source
Je choisis en fonction de la lisibilité. Je préfère l'option de format lorsqu'il y a du texte autour des variables. Dans cet exemple:
vous comprenez la signification même sans noms de variables, alors que le concat est encombré de guillemets et de signes + et me trouble les yeux:
(J'ai emprunté l'exemple de Mike parce que je l'aime bien)
Si la chaîne de format ne signifie pas grand-chose sans les noms de variables, je dois utiliser concat:
L'option de format me fait lire les noms de variables et les mapper aux nombres correspondants. L'option concat ne nécessite pas cela. Je suis toujours confus par les guillemets et les signes +, mais l'alternative est pire. Rubis?
En termes de performances, je m'attends à ce que l'option de format soit plus lente que le concat, car le format nécessite que la chaîne soit analysée . Je ne me souviens pas avoir à optimiser ce type d'instruction, mais si je le faisais, je regarderais des
string
méthodes commeConcat()
etJoin()
.L'autre avantage du format est que la chaîne de format peut être placée dans un fichier de configuration. Très pratique avec les messages d'erreur et le texte de l'interface utilisateur.
la source
J'utiliserais le String.Format, mais j'aurais également la chaîne de format dans les fichiers de ressources afin qu'elle puisse être localisée pour d'autres langues. L'utilisation d'une simple chaîne concat ne vous permet pas de le faire. Évidemment, si vous n'aurez jamais besoin de localiser cette chaîne, ce n'est pas une raison d'y penser. Cela dépend vraiment de ce à quoi sert la chaîne.
Si cela doit être montré à l'utilisateur, j'utiliserais String.Format pour que je puisse localiser si nécessaire - et FxCop le vérifiera pour moi, juste au cas où :)
S'il contient des nombres ou d'autres choses non-string (par exemple des dates), j'utiliserais String.Format car cela me donne plus de contrôle sur la mise en forme .
Si c'est pour créer une requête comme SQL, j'utiliserais Linq .
Si pour concaténer des chaînes dans une boucle, j'utiliserais StringBuilder pour éviter les problèmes de performances.
Si c'est pour une sortie que l'utilisateur ne verra pas et que cela n'affectera pas les performances, j'utiliserais String.Format parce que j'ai l'habitude de l'utiliser de toute façon et que je suis juste habitué :)
la source
Si vous avez affaire à quelque chose qui doit être facile à lire (et c'est la plupart du code), je m'en tiendrai à la version de surcharge de l'opérateur SAUF:
Dans au moins deux de ces circonstances, j'utiliserais StringBuilder à la place.
la source
Si vous avez l'intention de localiser le résultat, String.Format est essentiel car différents langages naturels peuvent même ne pas avoir les données dans le même ordre.
la source
Je pense que cela dépend fortement de la complexité de la sortie. J'ai tendance à choisir le scénario qui fonctionne le mieux à l'époque.
Choisissez le bon outil en fonction du travail: D Celui qui semble le plus propre!
la source
Je préfère également le second, mais je n'ai pas d'arguments rationnels pour le moment pour étayer cette position.
la source
Joli!
Vient d'ajouter
Et c'est encore plus rapide (je suppose que string.Concat est appelé dans les deux exemples, mais le premier nécessite une sorte de traduction).
la source
string.Concat(...)
. Elle est effectuée lors de la compilation et n'a donc aucun impact sur les performances d'exécution. Si vous exécutez vos tests plusieurs fois ou si vous les exécutez sur des échantillons de test plus grands, vous verrez qu'ils sont identiques.Puisque je ne pense pas que les réponses ici couvrent tout, j'aimerais faire un petit ajout ici.
Console.WriteLine(string format, params object[] pars)
appelsstring.Format
. Le «+» implique la concaténation de chaînes. Je ne pense pas que cela ait toujours à voir avec le style; J'ai tendance à mélanger les deux styles en fonction du contexte dans lequel je suis.Réponse courte
La décision à laquelle vous êtes confronté concerne l'allocation de chaînes. Je vais essayer de faire simple.
Dis que tu as
Si vous exécutez ceci, il évaluera comme suit:
tmp
ici, ce n'est pas vraiment une variable locale, mais c'est une variable temporaire pour le JIT (elle est poussée sur la pile IL). Si vous poussez une chaîne sur la pile (telle queldstr
dans IL pour les littéraux), vous placez une référence à un pointeur de chaîne sur la pile.Le moment où vous appelez
concat
cette référence devient un problème, car il n'y a pas de référence de chaîne disponible contenant les deux chaînes. Cela signifie que .NET doit allouer un nouveau bloc de mémoire, puis le remplir avec les deux chaînes. La raison pour laquelle c'est un problème, c'est que l'attribution est relativement chère.Ce qui change la question en: Comment pouvez-vous réduire le nombre d'
concat
opérations?Donc, la réponse approximative est:
string.Format
pour> 1 concat, '+' fonctionnera très bien pour 1 concat. Et si vous ne vous souciez pas de faire des optimisations de micro-performances,string.Format
cela fonctionnera très bien dans le cas général.Une note sur la culture
Et puis il y a quelque chose qui s'appelle la culture ...
string.Format
vous permet d'utiliserCultureInfo
dans votre mise en forme. Un simple opérateur «+» utilise la culture actuelle.C'est particulièrement une remarque importante si vous écrivez des formats de fichiers et f.ex.
double
les valeurs que vous «ajoutez» à une chaîne. Sur différentes machines, vous pourriez vous retrouver avec des chaînes différentes si vous ne l'utilisez passtring.Format
avec un fichier expliciteCultureInfo
.Par ex. considérez ce qui se passe si vous changez un '.' pour un ',' lors de l'écriture de votre fichier de valeurs séparées par des virgules ... en néerlandais, le séparateur décimal est une virgule, donc votre utilisateur pourrait juste avoir une 'drôle' surprise.
Réponse plus détaillée
Si vous ne connaissez pas la taille exacte de la chaîne au préalable, il est préférable d'utiliser une stratégie comme celle-ci pour surallouer les tampons que vous utilisez. L'espace libre est d'abord rempli, après quoi les données sont copiées.
Croître signifie allouer un nouveau bloc de mémoire et copier les anciennes données dans le nouveau tampon. L'ancien bloc de mémoire peut alors être libéré. Vous obtenez le résultat final à ce stade: la culture est une opération coûteuse.
Le moyen le plus pratique de procéder consiste à utiliser une politique de surutilisation. La politique la plus courante consiste à surallouer les tampons en puissances de 2. Bien sûr, vous devez le faire un peu plus intelligemment que cela (car cela n'a aucun sens de passer de 1,2,4,8 si vous savez déjà que vous avez besoin de 128 caractères ) Mais tu vois ce que je veux dire. La politique garantit que vous n'avez pas besoin d'un trop grand nombre des opérations coûteuses que j'ai décrites ci-dessus.
StringBuilder
est une classe qui surutilise essentiellement le tampon sous-jacent en puissances de deux.string.Format
utiliseStringBuilder
sous le capot.Cela fait de votre décision un compromis de base entre surallouer et ajouter (-multiple) (w / wo culture) ou simplement allouer et ajouter.
la source
Personnellement, le second, car tout ce que vous utilisez est dans l'ordre direct dans lequel il sera affiché. Alors qu'avec le premier, vous devez faire correspondre les {0} et {1} avec la variable appropriée, ce qui est facile à gâcher.
Au moins, ce n'est pas aussi mauvais que le sprintf C ++ où si vous obtenez le mauvais type de variable, tout explosera.
De plus, comme le second est entièrement en ligne et qu'il n'a pas à faire de recherche et de remplacement pour toutes les {0} choses, ce dernier devrait être plus rapide ... même si je ne sais pas avec certitude.
la source
J'aime en fait le premier car quand il y a beaucoup de variables entremêlées avec le texte, il me semble plus facile à lire. De plus, il est plus facile de traiter les guillemets lors de l'utilisation de la chaîne.Format (), euh, format. Voici une analyse décente de la concaténation de chaînes.
la source
J'ai toujours suivi la route string.Format (). Pouvoir stocker des formats dans des variables comme l'exemple de Nathan est un grand avantage. Dans certains cas, je peux ajouter une variable mais une fois plus d'une variable est concaténée, je refactorise pour utiliser le formatage.
la source
Oh, et juste pour être complet, ce qui suit est quelques ticks plus rapides que la concaténation normale:
la source
Le premier (format) me semble meilleur. Il est plus lisible et vous ne créez pas d'objets chaîne temporaires supplémentaires.
la source
J'étais curieux de savoir où en était StringBuilder avec ces tests. Résultats ci-dessous ...
Résultats:
la source
Selon le matériel de préparation MCSD, Microsoft suggère d'utiliser l'opérateur + pour traiter un très petit nombre de concaténations (probablement 2 à 4). Je ne sais toujours pas pourquoi, mais c'est quelque chose à considérer.
la source