Domanda

Qual è il modo più efficiente per concatenare le stringhe?

È stato utile?

Soluzione

IL StringBuilder.Append() Il metodo è molto migliore rispetto all'utilizzo dell'operatore +.Ma ho scoperto che, quando si eseguono 1000 concatenazioni o meno, String.Join() è ancora più efficiente di StringBuilder.

StringBuilder sb = new StringBuilder();
sb.Append(someString);

L'unico problema con String.Join è che devi concatenare le stringhe con un delimitatore comune.(Modifica :) come ha sottolineato @ryanversaw, puoi creare la stringa delimitatrice.Empty.

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

Altri suggerimenti

Rico Mariani, il guru delle prestazioni .NET, aveva un articolo proprio su questo argomento.Non è così semplice come si potrebbe sospettare.Il consiglio fondamentale è questo:

Se il tuo modello è simile a:

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

questo è un concat ed è scattante, StringBuilder probabilmente non aiuterà.

Se il tuo modello è simile a:

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

allora probabilmente vorrai StringBuilder.

Ancora un altro articolo a sostegno di questa affermazione proviene da Eric Lippert dove descrive le ottimizzazioni eseguite su una riga + concatenazioni in modo dettagliato.

Esistono 6 tipi di concatenazioni di stringhe:

  1. Utilizzando il segno più (+) simbolo.
  2. Utilizzando string.Concat().
  3. Utilizzando string.Join().
  4. Utilizzando string.Format().
  5. Utilizzando string.Append().
  6. Utilizzando StringBuilder.

In un esperimento è stato dimostrato string.Concat() è il modo migliore per avvicinarsi se le parole sono meno di 1000 (approssimativamente) e se le parole sono più di 1000 allora StringBuilder dovrebbe essere usato.

Per ulteriori informazioni, controlla questo luogo.

string.Join() vs string.Concat()

Il metodo string.Concat qui è equivalente all'invocazione del metodo string.Join con un separatore vuoto.Aggiungere una stringa vuota è veloce, ma non farlo è ancora più veloce, quindi il file stringa.Concat il metodo sarebbe superiore qui.

Da Chinh Do - StringBuilder non è sempre più veloce:

Regole empiriche

  • Quando si concatenano tre valori di stringa dinamici o meno, utilizzare la concatenazione di stringhe tradizionale.

  • Quando si concatenano più di tre valori di stringa dinamici, utilizzare StringBuilder.

  • Quando si crea una stringa di grandi dimensioni da diverse stringhe letterali, utilizzare il valore letterale @string o l'operatore inline +.

Maggior parte del tempo StringBuilder è la soluzione migliore, ma ci sono casi come mostrato in quel post in cui dovresti almeno pensare a ogni situazione.

Se stai operando in loop, StringBuilder è probabilmente la strada da percorrere;ti risparmia il sovraccarico di creare regolarmente nuove stringhe.Nel codice che verrà eseguito solo una volta, però, String.Concat probabilmente va bene.

Tuttavia, Rico Mariani (guru dell'ottimizzazione .NET) preparato un quiz in cui alla fine ha affermato che, nella maggior parte dei casi, consiglia String.Format.

Ecco il metodo più veloce che ho sviluppato in un decennio per la mia app di PNL su larga scala.Ho delle varianti per IEnumerable<T> e altri tipi di input, con e senza separatori di diverso tipo (Char, String), ma qui mostro il semplice caso di concatenando tutte le stringhe in un array in un'unica stringa, senza separatore.L'ultima versione qui è sviluppata e testata dall'unità Do#7 E .NET 4.7.

Esistono due chiavi per ottenere prestazioni più elevate;il primo è precalcolare l'esatta dimensione totale richiesta.Questo passaggio è banale quando l'input è un array come mostrato qui.Per la manipolazione IEnumerable<T> vale invece la pena raccogliere prima le stringhe in un array temporaneo per calcolare il totale (l'array è necessario per evitare chiamate ToString() più di una volta per elemento poiché tecnicamente, data la possibilità di effetti collaterali, ciò potrebbe modificare la semantica prevista di un'operazione di 'unione di stringhe').

Successivamente, data la dimensione totale dell'allocazione della stringa finale, il maggiore incremento delle prestazioni si ottiene da costruendo la stringa del risultato sul posto.Per fare ciò è necessaria la tecnica (forse controversa) di sospendere temporaneamente l’immutabilità di una cosa nuova String che inizialmente è assegnato pieno di zeri.A parte ogni controversia del genere, però...

...nota che questa è l'unica soluzione di concatenazione di massa in questa pagina che evita completamente un giro extra di assegnazione e copia dal String costruttore.

Codice completo:

/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
    int i;
    if (rg == null || (i = rg.Length) == 0)
        return String.Empty;

    if (i == 1)
        return rg[0];

    String s, t;
    int cch = 0;
    do
        cch += rg[--i].Length;
    while (i > 0);
    if (cch == 0)
        return String.Empty;

    i = rg.Length;
    fixed (Char* _p = (s = new String(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);

Dovrei dire che questo codice ha una leggera modifica rispetto a quello che uso io stesso.Nell'originale, I chiama il cpblk Istruzioni IL da C# per eseguire la copia vera e propria.Per semplicità e portabilità nel codice qui, l'ho sostituito con P/Invoke memcpy invece, come puoi vedere.Per le massime prestazioni su x64 (ma forse non x86) potresti voler usare il file cpblk metodo invece.

Da questa Articolo MSDN:

C'è un po 'di spese generali associate alla creazione di un oggetto StringBuilder, sia nel tempo che nella memoria.Su una macchina con memoria veloce, un costruttore di stringa vale la pena fare circa cinque operazioni.Come regola generale, direi che 10 o più operazioni di stringa sono una giustificazione per le spese generali su qualsiasi macchina, anche più lenta.

Quindi, se ti fidi di MSDN, vai con StringBuilder se devi eseguire più di 10 operazioni/concatenazioni di stringhe, altrimenti va bene un semplice concatenamento di stringhe con "+".

In aggiunta alle altre risposte, tienilo presente È possibile indicare a StringBuilder una quantità iniziale di memoria da allocare.

IL capacità Il parametro definisce il numero massimo di caratteri che possono essere archiviati nella memoria allocata dall'istanza corrente.Il suo valore è assegnato a Capacità proprietà.Se il numero di caratteri da memorizzare nell'istanza corrente supera questo valore capacità valore, l'oggetto StringBuilder alloca memoria aggiuntiva per archiviarli.

Se capacità è zero, viene utilizzata la capacità predefinita specifica dell'implementazione.

L'aggiunta ripetuta a uno StringBuilder che non è stato pre-allocato può comportare molte allocazioni non necessarie, proprio come la concatenazione ripetuta di stringhe regolari.

Se sai quanto sarà lunga la stringa finale, puoi calcolarla banalmente o fare un'ipotesi plausibile sul caso comune (allocare troppo non è necessariamente una cosa negativa), dovresti fornire queste informazioni al costruttore o al Capacità proprietà. Particolarmente quando si eseguono test delle prestazioni per confrontare StringBuilder con altri metodi come String.Concat, che fanno la stessa cosa internamente.Qualsiasi test che vedi online che non include la preallocazione di StringBuilder nei suoi confronti è sbagliato.

Se non riesci a fare alcuna ipotesi sulla dimensione, probabilmente stai scrivendo una funzione di utilità che dovrebbe avere un proprio argomento opzionale per controllare la pre-allocazione.

È anche importante sottolineare che dovresti usare il file + operatore se stai concatenando stringhe letterali.

Quando si concatenano valori letterali stringa o costanti stringa utilizzando l'operatore +, il compilatore crea una singola stringa.Non si verifica alcuna concatenazione in fase di esecuzione.

Come:Concatenare più stringhe (Guida per programmatori C#)

Di seguito potrebbe esserci un'altra soluzione alternativa per concatenare più stringhe.

String str1 = "sometext";
string str2 = "some other text";

string afterConcate = $"{str1}{str2}";

interpolazione di stringhe

Il più efficiente è usare StringBuilder, in questo modo:

StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();

@jonezy:String.Concat va bene se hai un paio di piccole cose.Ma se stai concatenando megabyte di dati, è probabile che il tuo programma si riempia.

Prova questi 2 pezzi di codice e troverai la soluzione.

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

Contro

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

Scoprirai che il primo codice terminerà molto velocemente e la memoria sarà in buona quantità.

Il secondo codice forse la memoria andrà bene, ma ci vorrà più tempo...molto più a lungo.Quindi, se hai un'applicazione per molti utenti e hai bisogno di velocità, usa la prima.Se disponi di un'app per un utente a breve termine, forse puoi utilizzarli entrambi o il secondo sarà più "naturale" per gli sviluppatori.

Saluti.

System.String è immutabile.Quando modifichiamo il valore di una variabile stringa, una nuova memoria viene allocata al nuovo valore e la precedente allocazione di memoria viene rilasciata.System.StringBuilder è stato progettato per avere il concetto di una stringa modificabile in cui è possibile eseguire una varietà di operazioni senza allocare una posizione di memoria separata per la stringa modificata.

Un'altra soluzione:

all'interno del ciclo, usa List invece di string.

List<string> lst= new List<string>();

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

è molto molto veloce.

Dipende davvero dal tuo modello di utilizzo.Un benchmark dettagliato tra string.Join, string,Concat e string.Format può essere trovato qui: String.Format non è adatto alla registrazione intensiva

(Questa è in realtà la stessa risposta che ho dato Questo domanda)

Per solo due stringhe, sicuramente non vorrai utilizzare StringBuilder.Esiste una soglia al di sopra della quale l'overhead di StringBuilder è inferiore all'overhead derivante dall'allocazione di più stringhe.

Quindi, per più di 2-3 corde, utilizzare Il codice di DannySmurf.Altrimenti usa semplicemente l'operatore +.

Dipenderebbe dal codice.StringBuilder è generalmente più efficiente, ma se stai concatenando solo poche stringhe e facendo tutto in una riga, è probabile che le ottimizzazioni del codice se ne occupino per te.È importante pensare anche a come appare il codice:per set più grandi StringBuilder renderà più facile la lettura, per quelli piccoli StringBuilder aggiungerà semplicemente confusione inutile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top