Domanda

Mi chiedevo di StringBuilder e ho una domanda che speravo la comunità sarebbe stata in grado di spiegare.

Diciamo solo dimenticare la leggibilità del codice, quale di questi è più veloce e perché?

StringBuilder.Append:

StringBuilder sb = new StringBuilder();
sb.Append(string1);
sb.Append("----");
sb.Append(string2);

StringBuilder.AppendFormat:

StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}----{1}",string1,string2);
È stato utile?

Soluzione

E 'impossibile dire, non sapendo la dimensione del string1 e string2.

Con la chiamata a AppendFormat , esso preallocare buffer sola volta determinata la lunghezza della stringa di formato e le stringhe che verranno inseriti e quindi concatenare tutto e inserirla nel buffer. Per molto stringhe di grandi dimensioni, questo sarà vantaggioso rispetto alle chiamate separate per Append che potrebbe causare il buffer di espandersi più volte.

Tuttavia, le tre chiamate a Append potrebbe o non potrebbe innescare la crescita del buffer e che controllo viene eseguito ogni chiamata. Se le stringhe sono abbastanza piccoli e non di espansione del buffer viene attivato, allora sarà più veloce della chiamata a AppendFormat, perché non dovrà analizzare la stringa di formato per capire dove fare le sostituzioni.

è necessario

Più dati per una risposta definitiva

Si dovrebbe notare che c'è poca discussione di usare la statica metodo Concat sulla classe String ( di Jon risposta utilizzando AppendWithCapacity mi ha ricordato di questo). I suoi risultati dei test mostrano che, per essere il caso migliore (ammesso che non c'è bisogno di usufruire di formato specifico identificatore). String.Concat fa la stessa cosa che possa predeterminare la lunghezza delle stringhe per concatenare e preallocare il buffer (con leggermente più in alto a causa di costrutti di loop i parametri). E 'prestazioni sta per essere paragonabile a metodo AppendWithCapacity di Jon.

O, semplicemente dell'operatore di addizione semplice, perché compila per una chiamata a String.Concat comunque, con l'avvertenza che tutte le aggiunte sono nella stessa espressione:

// One call to String.Concat.
string result = a + b + c;

non

// Two calls to String.Concat.
string result = a + b;
result = result + c;

Per tutti coloro tirare sul codice di prova

È necessario eseguire i vostri casi di test in separato run (o almeno, eseguire un GC tra la misura del test separato viene eseguito). La ragione di questo è che se non dici, 1.000.000 di piste, la creazione di una nuova StringBuilder in ogni iterazione del ciclo per un test, e quindi si esegue il test successivo che loop lo stesso numero di volte, creando un em> ulteriori em> 1.000.000 casi StringBuilder <

Altri suggerimenti

casperOne è corretto . Una volta raggiunta una certa soglia, il metodo Append() diventa più lento di AppendFormat(). Qui ci sono le diverse lunghezze e le zecche trascorsi di 100.000 iterazioni di ogni metodo:

Durata: 1

Append()       - 50900
AppendFormat() - 126826

Lunghezza: 1000

Append()       - 1241938
AppendFormat() - 1337396

Lunghezza: 10.000

Append()       - 12482051
AppendFormat() - 12740862

Lunghezza: 20,000

Append()       - 61029875
AppendFormat() - 60483914

Quando si introducono le stringhe di lunghezza nei pressi di 20.000, la funzione AppendFormat() sarà un po ' Append() outperform.

Perché accade questo? Vedi di casperOne risposta .

Modifica

I reran ogni test singolarmente in configurazione di rilascio e aggiornato i risultati.

casperOne è del tutto esatto che dipende dai dati . Tuttavia, supponiamo che si sta scrivendo questo come una libreria di classi per 3 parti di consumare -? Che si usa

Una possibilità sarebbe quella di ottenere il meglio dei due mondi - lavora fuori la quantità di dati si sta effettivamente andando ad avere per aggiungere, e quindi utilizzare StringBuilder.EnsureCapacity per assicurarsi che abbiamo solo bisogno di un singolo ridimensionamento del buffer.

Se non fossi anche infastidito, però, mi piacerebbe utilizzare Append x3 - sembra "più probabile" per essere più veloce, come l'analisi dei token di formato stringa su ogni chiamata è chiaramente make-lavoro .

Si noti che ho chiesto alla squadra BCL per una sorta di "formattatore cache", che potremmo creare utilizzando una stringa di formato e poi ri-uso ripetutamente. E 'pazzesco che il quadro deve analizzare la stringa di formato ogni volta che viene utilizzato.

EDIT: Okay, ho modificato il codice di John un po 'di flessibilità e aggiunto un "AppendWithCapacity" che funziona appena fuori la capacità necessaria prima. Ecco i risultati per le diverse lunghezze - per la lunghezza 1 ho usato 1.000.000 iterazioni; per tutte le altre lunghezze ho usato 100.000. (Questo è stato solo per ottenere tempi di esecuzione sensibili.) Tutti gli orari sono a Millis.

Purtroppo tabelle non funzionano veramente in SO. Le lunghezze sono stati 1, 1000, 10000, 20000

Tempi:

  • Aggiungi: 162, 475, 7997, 17970
  • AppendFormat: 392, 499, 8541, 18993
  • AppendWithCapacity: 139, 189, 1558, 3085

Così come è successo, non ho mai visto AppendFormat battere Append -. Ma I ha vedere AppendWithCapacity vincere con un margine molto consistente

Ecco il codice completo:

using System;
using System.Diagnostics;
using System.Text;

public class StringBuilderTest
{            
    static void Append(string string1, string string2)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append(string1);
        sb.Append("----");
        sb.Append(string2);
    }

    static void AppendWithCapacity(string string1, string string2)
    {
        int capacity = string1.Length + string2.Length + 4;
        StringBuilder sb = new StringBuilder(capacity);
        sb.Append(string1);
        sb.Append("----");
        sb.Append(string2);
    }

    static void AppendFormat(string string1, string string2)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendFormat("{0}----{1}", string1, string2);
    }

    static void Main(string[] args)
    {
        int size = int.Parse(args[0]);
        int iterations = int.Parse(args[1]);
        string method = args[2];

        Action<string,string> action;
        switch (method)
        {
            case "Append": action = Append; break;
            case "AppendWithCapacity": action = AppendWithCapacity; break;
            case "AppendFormat": action = AppendFormat; break;
            default: throw new ArgumentException();
        }

        string string1 = new string('x', size);
        string string2 = new string('y', size);

        // Make sure it's JITted
        action(string1, string2);
        GC.Collect();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < iterations; i++)
        {
            action(string1, string2);
        }
        sw.Stop();
        Console.WriteLine("Time: {0}ms", (int) sw.ElapsedMilliseconds);
    }
}

Append sarà più veloce in maggior parte dei casi perché ci sono molti sovraccarichi a quel metodo che permette al compilatore di chiamare il metodo corretto. Dal momento che si sta utilizzando il Strings StringBuilder può utilizzare l'overload String per Append.

AppendFormat prende un String e poi un Object[] che significa che il formato dovrà essere analizzato e ogni Object nella matrice dovranno essere ToString'd prima che possa essere aggiunto alla matrice interna StringBuilder's.

Nota: Per punto di casperOne - è difficile dare una risposta precisa, senza ulteriori dati

.

StringBuilder accodamento ha anche in cascata: Append() restituisce il StringBuilder stesso, in modo da poter scrivere il codice in questo modo:

StringBuilder sb = new StringBuilder();
sb.Append(string1)
  .Append("----")
  .Append(string2);

Clean, e genera meno IL-codice (anche se questo è davvero un micro-ottimizzazione).

Di profilo corso per sapere con certezza in ogni caso.

Detto questo, credo che in generale sarà il primo perché non si è più volte l'analisi della stringa di formato.

Tuttavia, la differenza sarebbe molto piccola. Al punto che si dovrebbe considerare l'utilizzo di AppendFormat nella maggior parte dei casi comunque.

I piacerebbe pensare che era la chiamata che ha fatto la minor quantità di lavoro. Aggiunge solo concatena le stringhe, dove AppendFormat sta facendo la sostituzione delle stringhe. Naturalmente in questi giorni, non si può mai dire ...

1 dovrebbe essere più veloce perché è semplicemente aggiungendo le corde, mentre 2 deve creare una stringa basata su un formato e quindi aggiungere la stringa. Quindi c'è un passo in più in là.

Più veloce è 1 nel tuo caso però non si tratta di un confronto equo. Si dovrebbe chiedere StringBuilder.AppendFormat () vs StringBuilder.Append (string.Format ()) -. In cui il primo è più veloce a causa di lavoro interno con array di caratteri

La seconda opzione è più leggibile però.

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