Moyen le plus efficace pour concaténer des chaînes?

Quel est le moyen le plus efficace de concaténer des chaînes?

La méthode SsortingngBuilder.Append() 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, Ssortingng.Join() est encore plus efficace que SsortingngBuilder .

 SsortingngBuilder sb = new SsortingngBuilder(); sb.Append(someSsortingng); 

Le seul problème avec Ssortingng.Join est que vous devez concaténer les chaînes avec un délimiteur commun. (Edit 🙂 comme @ryanversaw l’a souligné, vous pouvez créer la chaîne de délimitation. Vide.

 ssortingng key = Ssortingng.Join("_", new Ssortingng[] { "Customers_Contacts", customerID, database, SessionID }); 

Rico Mariani , le gourou des performances .NET, a publié un article sur ce sujet. Ce n’est pas aussi simple qu’on pourrait le penser. Le conseil de base est le suivant:

Si votre modèle ressemble à:

x = f1(...) + f2(...) + f3(...) + f4(...)

c’est un concat et c’est zippy, SsortingngBuilder ne sera probablement pas utile.

Si votre modèle ressemble à:

if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)

alors vous voulez probablement SsortingngBuilder.

Un autre article à l’appui de cette affirmation vient d’Eric Lippert où il décrit les optimisations effectuées sur une ligne + concaténations de manière détaillée.

Il existe 6 types de concaténations de chaînes:

  1. En utilisant le symbole plus ( + ).
  2. En utilisant ssortingng.Concat() .
  3. En utilisant ssortingng.Join() .
  4. Utiliser ssortingng.Format() .
  5. Utiliser ssortingng.Append() .
  6. Utiliser SsortingngBuilder .

Dans une expérience, il a été prouvé que ssortingng.Concat() est la meilleure façon de s’approcher si les mots sont inférieurs à 1000 (approximativement) et si les mots sont supérieurs à 1000, alors SsortingngBuilder doit être utilisé.

Pour plus d’informations, consultez ce site .

ssortingng.Join () vs ssortingng.Concat ()

La méthode ssortingng.Concat ici est équivalente à l’appel de la méthode ssortingng.Join avec un séparateur vide. Ajouter une chaîne vide est rapide, mais ne pas le faire est encore plus rapide, donc la méthode ssortingng.Concat serait supérieure ici.

De Chinh Do – SsortingngBuilder n’est pas toujours plus rapide :

Règles de base

  • Lors de la concaténation de trois valeurs de chaîne dynamic ou moins, utilisez la concaténation de chaîne traditionnelle.

  • Lors de la concaténation de plus de trois valeurs de chaîne dynamic, utilisez SsortingngBuilder.

  • Lors de la création d’une grande chaîne à partir de plusieurs littéraux de chaîne, utilisez le littéral @ ssortingng ou l’opérateur inline +.

La plupart du temps, SsortingngBuilder est votre meilleur pari, mais il y a des cas comme montré dans cet article que vous devriez au moins penser à chaque situation.

Si vous travaillez en boucle, SsortingngBuilder est probablement la voie à suivre. Cela vous évite de créer régulièrement de nouvelles chaînes. Dans le code qui ne sera exécuté qu’une seule fois, Ssortingng.Concat est probablement correct.

Cependant, Rico Mariani (gourou de l’optimisation .NET) a rédigé un questionnaire dans lequel il a déclaré à la fin que, dans la plupart des cas, il recommandait Ssortingng.Format.

À partir de cet article MSDN :

La création d’un object SsortingngBuilder, à la fois dans le temps et dans la mémoire, est associée à une surcharge. Sur une machine avec une mémoire rapide, un SsortingngBuilder vaut la peine si vous effectuez environ cinq opérations. En règle générale, je dirais que 10 opérations de chaîne ou plus sont une justification de la surcharge pour toute machine, même plus lente.

Donc, si vous faites confiance à MSDN, utilisez SsortingngBuilder si vous devez effectuer plus de 10 opérations / concaténations de chaînes.

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 variantes pour IEnumerable et d’autres types d’entrées, avec et sans séparateurs de types différents ( Char , Ssortingng ), mais je montre ici le cas simple de la concaténation de toutes les chaînes dans un tableau sans séparateur. La dernière version ici est développée et testée sur C # 7 et .NET 4.7 .

Il y a deux clés à une meilleure performance. La première consiste à pré-calculer la taille totale exacte requirejse. Cette étape est sortingviale lorsque l’entrée est un tableau, comme indiqué ici. Pour gérer IEnumerable , il est préférable de rassembler les chaînes dans un tableau temporaire pour calculer ce total (le tableau est nécessaire pour éviter d’appeler ToSsortingng() plus d’une fois par élément, techniquement, compte tenu des effets secondaires, cela pourrait changer la sémantique attendue d’une opération de “jointure de chaîne”).

Ensuite, compte tenu de la taille d’allocation totale de la chaîne finale, la plus grande amélioration des performances est obtenue en générant la chaîne de résultat en place . Faire cela nécessite la technique (peut-être controversée) de suspendre temporairement l’immuabilité d’une nouvelle Ssortingng qui est initialement allouée pleine de zéros. Une telle controverse mise à part, cependant …

… notez qu’il s’agit de la seule solution de concaténation en bloc sur cette page, qui évite complètement un tour supplémentaire d’allocation et de copie par le constructeur Ssortingng .

Code complet:

 ///  /// Concatenate the ssortingngs in 'rg', none of which may be null, into a single Ssortingng. ///  public static unsafe Ssortingng SsortingngJoin(this Ssortingng[] rg) { int i; if (rg == null || (i = rg.Length) == 0) return Ssortingng.Empty; if (i == 1) return rg[0]; Ssortingng s, t; int cch = 0; do cch += rg[--i].Length; while (i > 0); if (cch == 0) return Ssortingng.Empty; i = rg.Length; fixed (Char* _p = (s = new Ssortingng(default(Char), cch))) { Char* pDst = _p + cch; do if ((t = rg[--i]).Length > 0) fixed (Char* pSrc = t) memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1)); while (pDst > _p); } return s; } [DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)] static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb); 

Je devrais 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 de C # pour effectuer la copie proprement dite. Pour plus de simplicité et de portabilité dans le code, j’ai remplacé cela par P / Invoke memcpy , comme vous pouvez le voir. Pour des performances optimales sur x64 ( mais peut-être pas sur x86 ), vous pouvez utiliser la méthode cpblk à la place.

Ajoutant aux autres réponses, veuillez garder à l’esprit que SsortingngBuilder peut recevoir une quantité initiale de mémoire à allouer .

Le paramètre Capacity définit le nombre maximal de caractères pouvant être stockés dans la mémoire allouée par l’instance actuelle. Sa valeur est affectée à la propriété Capacity . Si le nombre de caractères à stocker dans l’instance actuelle dépasse cette valeur de capacité , l’object SsortingngBuilder alloue de la mémoire supplémentaire pour les stocker.

Si la capacité est égale à zéro, la capacité par défaut spécifique à l’implémentation est utilisée.

L’ajout répété à un SsortingngBuilder qui n’a pas été pré-alloué peut entraîner de nombreuses allocations inutiles, 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, calculez-la de manière sortingviale ou faites une supposition éclairée sur le cas courant (allouer trop n’est pas forcément une mauvaise chose), vous devriez fournir ces informations au constructeur ou au Propriété de capacité . Surtout lors de l’exécution de tests de performances pour comparer SsortingngBuilder avec d’autres méthodes telles que Ssortingng.Concat, qui font la même chose en interne. Tout test que vous voyez en ligne et qui n’inclut pas la pré-allocation SsortingngBuilder dans ses comparaisons est incorrect.

Si vous ne pouvez pas deviner la taille, vous écrivez probablement une fonction utilitaire qui devrait avoir son propre argument optionnel pour contrôler la pré-allocation.

Il est également important de souligner que vous devez utiliser l’opérateur + si vous concaténez des littéraux de chaîne .

Lorsque vous concaténez des littéraux de chaîne ou des constantes de chaîne à l’aide de l’opérateur +, le compilateur crée une chaîne unique. Aucune concaténation à l’exécution n’a lieu.

Comment: concaténer plusieurs chaînes (Guide de programmation C #)

La suite peut être une autre solution alternative pour concaténer plusieurs chaînes.

 Ssortingng str1 = "sometext"; ssortingng str2 = "some other text"; ssortingng afterConcate = $"{str1}{str2}"; 

interpolation de chaîne

Le plus efficace est d’utiliser SsortingngBuilder, comme ceci:

 SsortingngBuilder sb = new SsortingngBuilder(); sb.Append("ssortingng1"); sb.Append("ssortingng2"); ...etc... Ssortingng strResult = sb.ToSsortingng(); 

@jonezy: Ssortingng.Concat c’est bien si vous avez quelques petites choses. Mais si vous concaténez des mégaoctets de données, votre programme risque de se bloquer.

Cela dépend vraiment de votre modèle d’utilisation. Un benchmark détaillé entre ssortingng.Join, ssortingng, Concat et ssortingng.Format peut être trouvé ici: Ssortingng.Format n’est pas adapté à la journalisation intensive

(C’est en fait la même réponse que j’ai donnée à cette question)

System.Ssortingng 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 est libérée. System.SsortingngBuilder a été conçu pour avoir le concept d’une chaîne mutable où diverses opérations peuvent être effectuées sans atsortingbution d’un emplacement de mémoire séparé pour la chaîne modifiée.

Essayez ces 2 morceaux de code et vous trouverez la solution.

  static void Main(ssortingng[] args) { SsortingngBuilder s = new SsortingngBuilder(); for (int i = 0; i < 10000000; i++) { s.Append( i.ToString()); } Console.Write("End"); Console.Read(); } 

Contre

 static void Main(ssortingng[] args) { ssortingng s = ""; for (int i = 0; i < 10000000; i++) { s += i.ToString(); } Console.Write("End"); Console.Read(); } 

Vous constaterez que le 1er code se terminera très vite et que la mémoire sera en bon état.

Le deuxième code peut-être que la mémoire sera correcte, mais cela prendra plus de temps ... beaucoup plus longtemps. Donc, si vous avez une application pour beaucoup d'utilisateurs et que vous avez besoin de rapidité, utilisez le 1er. Si vous avez une application pour une application utilisateur à court terme, vous pouvez peut-être utiliser les deux ou le 2ème sera plus "naturel" pour les développeurs.

À votre santé.

Pour deux chaînes seulement, vous ne voulez certainement pas utiliser SsortingngBuilder. Il existe un seuil au-dessus duquel la surcharge SsortingngBuilder est inférieure à la surcharge liée à l’allocation de plusieurs chaînes.

Donc, pour plus de 2-3 chaînes, utilisez le code de DannySmurf . Sinon, utilisez simplement l’opérateur +.

Cela dépend du code. SsortingngBuilder est généralement plus efficace, mais si vous concaténez seulement quelques chaînes et que vous le faites en une seule ligne, les optimisations de code en prendront probablement soin pour vous. Il est important de réfléchir à l’apparence du code: pour les ensembles plus grands, SsortingngBuilder facilitera la lecture, pour les petits, SsortingngBuilder appenda simplement de l’encombrement inutile.

Une autre solution:

dans la boucle, utilisez List au lieu de ssortingng.

 List lst= new List(); for(int i=0; i<100000; i++){ ........... lst.Add(...); } return String.Join("", lst.ToArray());; 

c'est très très rapide.