Quelle est la manière la plus efficace de concaténer des chaînes?
c#
.net
string
optimization
jimmij
la source
la source
StringBuilder
les cas d'utilisation peuvent être trouvées ici .String.Format
sur les stéroïdes. Ce qui, en termes de performances, est un tout petit peu plus lent sur une ligne que+
etString.Concat
, mais beaucoup mieux que ceux, bien que plus lent queStringBuilder
sur plusieurs appels. Pratiquement parlant, les différences de performances sont telles que, si je devais choisir une seule façon de concaténer, je choisirais les interpolations de chaînes en utilisant$
... Si deux façons, puis ajouterStringBuilder
à ma boîte à outils. Avec ces deux façons, vous êtes prêt.String.Join
réponse ci-dessous ne rend pas+
justice et est, en pratique, une mauvaise façon de concaténer des cordes, mais elle est étonnamment rapide en termes de performances. La réponse est intéressante.String.Concat
etString.Join
peut tous deux agir sur des tableaux, maisString.Join
est en fait plus rapide. Apparemment,String.Join
est assez sophistiqué et plus optimisé queString.Concat
, en partie parce qu'il fonctionne de la même manièreStringBuilder
qu'il calcule d'abord la longueur de la chaîne, puis construit la chaîne bénéficiant de ces connaissances à l'aide de UnSafeCharBuffer.String.Join
nécessite aussi de construire un tableau qui semble inefficace sur le plan des ressources, n'est-ce pas? ... Il s'avère que+
etString.Concat
construire des tableaux pour leurs constituants de toute façon. Par conséquent, la création manuelle d'un tableau et son alimentationString.Join
est relativement plus rapide ... cependant,StringBuilder
surpasse toujoursString.Join
de toutes les manières pratiques alors qu'il$
n'est que légèrement plus lent et beaucoup plus rapide sur les longues chaînes ... sans oublier qu'il est maladroit et laid à utiliserString.Join
si vous avez pour créer un tableau pour elle sur place.Réponses:
La
StringBuilder.Append()
méthode est bien meilleure que l'utilisation de l'+
opérateur. Mais j'ai trouvé que, lors de l'exécution de 1000 concaténations ou moins,String.Join()
c'est encore plus efficace queStringBuilder
.Le seul problème avec
String.Join
est que vous devez concaténer les chaînes avec un délimiteur commun.Edit: comme l' a souligné @ryanversaw , vous pouvez faire le délimiteur
string.Empty
.la source
StringBuilder
a un énorme coût de démarrage comparable, il n'est efficace que lorsqu'il est utilisé avec de très grandes chaînes ou de très nombreuses concaténations. Il n'est pas trivial de découvrir une situation donnée. Si les performances sont problématiques, le profilage est votre ami (voir ANTS).string.Concat
?Rico Mariani , le gourou de la performance .NET, avait un article sur ce même sujet. Ce n'est pas aussi simple qu'on pourrait le penser. Le conseil de base est le suivant:
Un autre article à l'appui de cette affirmation vient d'Eric Lippert où il décrit de
+
manière détaillée les optimisations effectuées sur des concaténations sur une ligne .la source
Il existe 6 types de concaténations de chaînes:
+
symbole plus ( ).string.Concat()
.string.Join()
.string.Format()
.string.Append()
.StringBuilder
.Dans une expérience, il a été prouvé que
string.Concat()
c'est la meilleure façon d'approcher si les mots sont inférieurs à 1000 (approximativement) et si les mots sont supérieurs à 1000 alorsStringBuilder
doivent être utilisés.Pour plus d'informations, consultez ce site .
la source
+
c'était en fait 3 millisecondes plus rapide questring.Concat()
, même si je n'ai pas examiné la quantité de chaînes nécessaires avant lesstring.Concat()
dépassements+
.Depuis Chinh Do - StringBuilder n'est pas toujours plus rapide :
Règles de base
Lors de la concaténation de trois valeurs de chaîne dynamique ou moins, utilisez la concaténation de chaîne traditionnelle.
Lors de la concaténation de plus de trois valeurs de chaîne dynamique, utilisez
StringBuilder
.Lorsque vous créez une grande chaîne à partir de plusieurs littéraux de chaîne, utilisez soit le
@
littéral de chaîne, soit l'opérateur inline +.La plupart du temps
StringBuilder
est votre meilleur pari, mais il y a des cas, comme indiqué dans ce post, que vous devriez au moins penser à chaque situation.la source
Si vous travaillez en boucle,
StringBuilder
c'est probablement la voie à suivre; cela vous évite d'avoir à créer régulièrement de nouvelles chaînes. Dans le code, cela ne fonctionnera qu'une seule fois,String.Concat
c'est probablement bien.Cependant, Rico Mariani (gourou de l'optimisation .NET) a composé un quiz dans lequel il a déclaré à la fin que, dans la plupart des cas, il recommande
String.Format
.la source
Voici la méthode la plus rapide que j'ai développée au cours d'une décennie pour mon application NLP à grande échelle. J'ai des variations pour
IEnumerable<T>
et d'autres types d'entrée, avec et sans séparateurs de différents types (Char
,String
), mais ici je montre le cas simple de la concaténation de toutes les chaînes d'un tableau en une seule chaîne, sans séparateur. La dernière version ici est développée et testée à l'unité sur C # 7 et .NET 4.7 .Il existe deux clés pour des performances plus élevées; la première consiste à pré-calculer la taille totale exacte requise. Cette étape est triviale lorsque l'entrée est un tableau comme illustré ici. Pour la gestion à la
IEnumerable<T>
place, il convient de rassembler d'abord les chaînes dans un tableau temporaire pour calculer ce total (le tableau est nécessaire pour éviter d'appelerToString()
plus d'une fois par élément car techniquement, étant donné la possibilité d'effets secondaires, cela pourrait changer la sémantique attendue d'une opération de "jointure de chaîne").Ensuite, étant donné la taille totale de l'allocation de la chaîne finale, la plus grande amélioration des performances est obtenue en créant la chaîne de résultat en place . Cela nécessite la technique (peut-être controversée) de suspendre temporairement l'immuabilité d'un nouveau
String
qui est initialement alloué plein de zéros. Une telle controverse mise à part, cependant ...Code complet:
Je dois mentionner que ce code a une légère modification de ce que j'utilise moi-même. Dans l'original, j'appelle l' instruction cpblk IL à partir de C # pour effectuer la copie réelle. Pour plus de simplicité et de portabilité dans le code ici, j'ai remplacé cela par P / Invoke à la
memcpy
place, comme vous pouvez le voir. Pour des performances optimales sur x64 ( mais peut-être pas x86 ), vous souhaiterez peut-être utiliser la méthode cpblk à la place.la source
string.Join
fait déjà toutes ces choses pour vous. Il n'est pas nécessaire de l'écrire vous-même. Il calcule la taille de la chaîne finale, construit une chaîne de cette taille, puis écrit dans le tableau de caractères sous-jacent. Il a même l'avantage d'utiliser des noms de variables lisibles dans le processus.String.Join
peut en effet être efficace. Comme je l'ai laissé entendre dans l'intro, le code ici n'est que l'illustration la plus simple d'une famille de fonctions que j'utilise pour des scénarios quiString.Join
ne gèrent pas (comme l'optimisation pour leChar
séparateur) ou ne le géraient pas dans les versions précédentes de .NET. Je suppose que je n'aurais pas dû choisir cela pour l'exemple le plus simple, car c'est un cas quiString.Join
gère déjà bien, bien qu'avec «l'inefficacité», probablement incommensurable, du traitement d'un séparateur vide, à savoir.String.Empty
.Concat
, ce qui le fait également correctement. De toute façon, vous n'avez pas besoin d'écrire le code vous-même.String.Join
mon code à l'aide de ce harnais de test . Pour 10 millions d'opérations de concaténation aléatoires contenant jusqu'à 100 chaînes de taille de mot chacune, le code ci-dessus est systématiquement 34% plus rapide queString.Join
sur la version x64 avec .NET 4.7 . Puisque l'OP demande explicitement la méthode "la plus efficace", le résultat suggère que ma réponse s'applique. Si cela répond à vos préoccupations, je vous invite à reconsidérer votre downvote.De cet article MSDN :
Donc, si vous faites confiance à MSDN, utilisez StringBuilder si vous devez effectuer plus de 10 opérations / concaténations de chaînes - sinon, une simple concaténation de chaînes avec «+» est très bien.
la source
Il est également important de souligner que vous devez utiliser l'
+
opérateur si vous concaténez des littéraux de chaîne .Comment: concaténer plusieurs chaînes (Guide de programmation C #)
la source
En ajoutant aux autres réponses, veuillez garder à l'esprit que StringBuilder peut recevoir une quantité initiale de mémoire à allouer .
L'ajout répété à un StringBuilder qui n'a pas été pré-alloué peut entraîner de nombreuses allocations inutiles, tout comme la concaténation répétée de chaînes régulières.
Si vous savez combien de temps durera la chaîne finale, pouvez la calculer trivialement ou faire une supposition éclairée sur le cas commun (allouer trop n'est pas nécessairement une mauvaise chose), vous devez fournir ces informations au constructeur ou au Propriété de capacité . Surtout lors de l'exécution de tests de performances pour comparer StringBuilder avec d'autres méthodes comme String.Concat, qui font la même chose en interne. Tout test que vous voyez en ligne qui n'inclut pas la pré-allocation de StringBuilder dans ses comparaisons est faux.
Si vous ne pouvez pas deviner la taille, vous écrivez probablement une fonction utilitaire qui devrait avoir son propre argument facultatif pour contrôler la pré-allocation.
la source
Voici peut-être une autre solution alternative pour concaténer plusieurs chaînes.
interpolation de chaîne
la source
String.Format
mais plus lisible et plus facile à utiliser. Banc-marquage, il est légèrement plus lent que+
etString.Concat
à une ligne de concaténations , mais beaucoup mieux que les deux personnes à des appels répétitifs rendantStringBuilder
moins nécessaire.Le plus efficace est d'utiliser StringBuilder, comme ceci:
@jonezy: String.Concat est très bien si vous avez quelques petites choses. Mais si vous concaténez des mégaoctets de données, votre programme sera probablement chargé.
la source
Essayez ces 2 morceaux de code et vous trouverez la solution.
Contre
Vous constaterez que le 1er code se terminera très rapidement et la mémoire sera en bonne quantité.
Le deuxième code peut-être que la mémoire sera correcte, mais cela prendra plus de temps ... beaucoup plus de temps. Donc, si vous avez une application pour beaucoup d'utilisateurs et que vous avez besoin de vitesse, utilisez la 1ère. Si vous avez une application pour une application utilisateur à court terme, vous pouvez peut-être utiliser les deux ou la seconde sera plus "naturelle" pour les développeurs.
À votre santé.
la source
Pour seulement deux chaînes, vous ne voulez certainement pas utiliser StringBuilder. Il existe un certain seuil au-dessus duquel la surcharge de StringBuilder est inférieure à la surcharge d'allocation de plusieurs chaînes.
Donc, pour plus de 2-3 chaînes, utilisez le code de DannySmurf . Sinon, utilisez simplement l'opérateur +.
la source
System.String est immuable. Lorsque nous modifions la valeur d'une variable de chaîne, une nouvelle mémoire est allouée à la nouvelle valeur et l'allocation de mémoire précédente libérée. System.StringBuilder a été conçu pour avoir le concept d'une chaîne mutable où une variété d'opérations peuvent être effectuées sans attribuer un emplacement de mémoire séparé pour la chaîne modifiée.
la source
Une autre solution:
à l'intérieur de la boucle, utilisez List au lieu de string.
c'est très très rapide.
la source
Cela dépend vraiment de votre modèle d'utilisation. Une référence détaillée entre string.Join, string, Concat et string.Format peut être trouvée ici: String.Format ne convient pas pour une journalisation intensive
(C'est en fait la même réponse que j'ai donnée à cette question)
la source
Cela dépendrait du code. StringBuilder est généralement plus efficace, mais si vous concaténez seulement quelques chaînes et faites tout cela sur une seule ligne, les optimisations de code s'en occuperont probablement pour vous. Il est important de penser à quoi ressemble le code: pour les ensembles plus grands, StringBuilder facilitera la lecture, pour les petits, StringBuilder ajoutera simplement un encombrement inutile.
la source