Ist die Verwendung String effiziente Methode mehr Speicher entfernen, als einen neuen Stringbuilder in Schleife zu schaffen?

StackOverflow https://stackoverflow.com/questions/266923

Frage

In C #, die mehr Speicher effizient ist: Option 1 oder Option 2

public void TestStringBuilder()
{
    //potentially a collection with several hundred items:
    string[] outputStrings = new string[] { "test1", "test2", "test3" };

    //Option #1
    StringBuilder formattedOutput = new StringBuilder();
    foreach (string outputString in outputStrings)
    {
        formattedOutput.Append("prefix ");
        formattedOutput.Append(outputString);
        formattedOutput.Append(" postfix");

        string output = formattedOutput.ToString();
        ExistingOutputMethodThatOnlyTakesAString(output);

        //Clear existing string to make ready for next iteration:
        formattedOutput.Remove(0, output.Length);
    }

    //Option #2
    foreach (string outputString in outputStrings)
    {
        StringBuilder formattedOutputInsideALoop = new StringBuilder();

        formattedOutputInsideALoop.Append("prefix ");
        formattedOutputInsideALoop.Append(outputString);
        formattedOutputInsideALoop.Append(" postfix");

        ExistingOutputMethodThatOnlyTakesAString(
           formattedOutputInsideALoop.ToString());
    }
}

private void ExistingOutputMethodThatOnlyTakesAString(string output)
{
    //This method actually writes out to a file.
    System.Console.WriteLine(output);
}
War es hilfreich?

Lösung

Einige der Antworten vorgeschlagen sanft, dass ich meine nutzlosen aussteigen und herauszufinden, es selbst sind so unter meinen Ergebnisse. Ich denke, dass sich die Stimmung geht in der Regel gegen den Strich dieser Seite, aber wenn Sie etwas richtig gemacht wollen, könnte man genauso gut tun ....:)

I modifizierte Option # 1 Vorteil @Ty Vorschlag zu nehmen StringBuilder.Length = 0 statt der Remove-Methode zu verwenden. Dies machte den Code der beiden Optionen mehr ähnlich. Die beiden Unterschiede sind nun, ob der Konstruktor für die Stringbuilder in oder aus der Schleife und Option # 1 nun die Länge Methode verwendet den String zu löschen. Beide Optionen wurden auf über eine outputStrings Array mit 100.000 Elementen laufen auf der Garbage Collector etwas Arbeit zu machen tun.

Ein paar Antworten angeboten Hinweise auf den verschiedenen PerfMon Zähler suchen und so und die Ergebnisse nutzen, um eine Option auszuwählen. Ich habe einige Nachforschungen und endete mit dem eingebauten in Performance Explorer der Visual Studio Team System Developer Edition, die ich bei der Arbeit habe. Ich fand den zweiten Blogeintrag einer mehrteiligen Serie, die erklärt, wie es einzurichten

Andere Tipps

Option 2 soll (ich glaube) tatsächlich outperform Option 1. Der Akt des Aufrufs Remove „zwingt“ der String eine Kopie des Strings nehmen Sie es bereits zurückgegeben. Der String ist eigentlich wandelbar in Stringbuilder und String nimmt nicht eine Kopie, wenn sie ihn braucht. Mit der Option 1 kopiert, bevor im Grunde aus dem Array Clearing - mit Option 2 keine Kopie erforderlich ist,

.

Der einzige Nachteil der Option 2 ist, dass, wenn die Zeichenfolge lange endet als, wird es gemacht mehrere Kopien sein, während das Anhängen - während Option 1 hält die ursprüngliche Größe des Puffers. Ist dies der Fall sein wird, jedoch geben Sie eine Anfangskapazität die zusätzliche Kopieren zu vermeiden. (In Ihrem Beispielcode wird die Zeichenfolge am Ende als größer als die Standard-16 Zeichen -. Es mit einer Kapazität von Initialisierung, sagen wir, 32 die zusätzlichen Saiten reduzieren, die erforderlich)

Neben der Leistung jedoch Option 2 ist nur sauberer.

Während der Profiler, könnten Sie auch versuchen, nur die Länge des String auf Null gesetzt werden, wenn Sie die Schleife ein.

formattedOutput.Length = 0;

Ich hasse es zu sagen, aber wie wäre es nur testen?

Dieses Zeug ist einfach selbst zu erfahren. Führen Sie Perfmon.exe und einen Zähler für .NET-Speicher + Gen 0 Sammlungen hinzufügen. Führen Sie den Testcode eine Million Mal. Sie werden sehen, dass Option # 1 die Hälfte der Anzahl von Sammlungen Option # 2 Bedarf erfordert.

Wir haben darüber gesprochen, bevor sie mit Java , ist hier die [Release] Ergebnisse der C # Version:

Option #1 (10000000 iterations): 11264ms
Option #2 (10000000 iterations): 12779ms

Update: In meiner nicht-wissenschaftlichen Analyse die beiden Methoden erlaubt, während der Ausführung Überwachung aller Speicherleistungsindikatoren in perfmon nicht mit beiden Methoden (außer ein paar Zählern mit Spike nur in jeder Art von erkennbarem Unterschied zur Folge hat, während entweder Test war ausgeführt wird).

Und hier ist, was ich Test verwendet:

class Program
{
    const int __iterations = 10000000;

    static void Main(string[] args)
    {
        TestStringBuilder();
        Console.ReadLine();
    }

    public static void TestStringBuilder()
    {
        //potentially a collection with several hundred items:
        var outputStrings = new [] { "test1", "test2", "test3" };

        var stopWatch = new Stopwatch();

        //Option #1
        stopWatch.Start();
        var formattedOutput = new StringBuilder();

        for (var i = 0; i < __iterations; i++)
        {
            foreach (var outputString in outputStrings)
            {
                formattedOutput.Append("prefix ");
                formattedOutput.Append(outputString);
                formattedOutput.Append(" postfix");

                var output = formattedOutput.ToString();
                ExistingOutputMethodThatOnlyTakesAString(output);

                //Clear existing string to make ready for next iteration:
                formattedOutput.Remove(0, output.Length);
            }
        }
        stopWatch.Stop();

        Console.WriteLine("Option #1 ({1} iterations): {0}ms", stopWatch.ElapsedMilliseconds, __iterations);
            Console.ReadLine();
        stopWatch.Reset();

        //Option #2
        stopWatch.Start();
        for (var i = 0; i < __iterations; i++)
        {
            foreach (var outputString in outputStrings)
            {
                StringBuilder formattedOutputInsideALoop = new StringBuilder();

                formattedOutputInsideALoop.Append("prefix ");
                formattedOutputInsideALoop.Append(outputString);
                formattedOutputInsideALoop.Append(" postfix");

                ExistingOutputMethodThatOnlyTakesAString(
                   formattedOutputInsideALoop.ToString());
            }
        }
        stopWatch.Stop();

        Console.WriteLine("Option #2 ({1} iterations): {0}ms", stopWatch.ElapsedMilliseconds, __iterations);
    }

    private static void ExistingOutputMethodThatOnlyTakesAString(string s)
    {
        // do nothing
    }
} 

Option 1 in diesem Szenario ist geringfügig schneller, obwohl die Option 2 ist leichter zu lesen und zu pflegen. Sofern Sie diese Operation Millionen Mal wieder passieren zu performen sichern ich mit Option würde Stick 2, weil ich diese Option 1 und 2 sind in etwa gleich vermuten, wenn sie in einer einzigen Iteration ausgeführt wird.

Ich würde sagen, Option # 2, wenn auf jeden Fall einfacher. In Bezug auf Leistung, klingt wie etwas würde man nur testen müssen und sehen. Ich würde vermuten, dass es nicht genug Unterschied macht das weniger einfach Option zu wählen.

Ich denke, die Option 1 würde etwas mehr sein Gedächtnis effizient wie ein neues Objekt wird nicht erstellt, jedes Mal. Having said that, hat der GC eine ziemlich gute Arbeit von Ressourcen wie in Option Reinigung 2.

Ich glaube, Sie können in die Falle der vorzeitigen Optimierung zu fallen ( die Wurzel allen Übels - -Knuth ). Ihr IO wird viel mehr Ressourcen als der String-Builder nehmen.

Ich neige dazu, mit der klareren / Reiniger Option gehen, in diesem Fall der Option 2.

Rob

  1. Messen Sie
  2. vorbelegen so nah wie möglich an, wie viel Speicher Sie denken, Sie müssen
  3. Wenn die Geschwindigkeit Ihre Präferenz ist, dann ein recht geradlinig Multi-Threaded vorne Mitte prüfen, mittlere gleichzeitigen Ansatz zu beenden (Arbeitsteilung erweitert je nach Bedarf)
  4. messen es wieder

Was ist wichtiger für Sie?

  1. Speicher

  2. Geschwindigkeit

  3. Klarheit

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top