Versuchen Sie diesen Code.
Es ist eine leicht modifizierte Version Ihres Codes.
1. Ich habe Console.WriteLine entfernt, da es wahrscheinlich einige Größenordnungen langsamer ist als das, was ich zu messen versuche.
2. Ich starte die Stoppuhr vor der Schleife und stoppe sie direkt danach. Auf diese Weise verliere ich nicht an Präzision, wenn die Ausführung der Funktion beispielsweise 26,4 Ticks benötigt.
3. Die Art und Weise, wie Sie das Ergebnis durch einige Iterationen geteilt haben, war falsch. Sehen Sie, was passiert, wenn Sie 1000 Millisekunden und 100 Millisekunden haben. In beiden Situationen erhalten Sie 0 ms, nachdem Sie es durch 1000000 geteilt haben.
Stopwatch s = new Stopwatch();
var p = new { FirstName = "Bill", LastName = "Gates" };
int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;
string result;
s.Start();
for (var i = 0; i < n; i++)
result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();
Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);
Das sind meine Ergebnisse:
1000000 x result = string.Format ("{0} {1}", p.FirstName, p.LastName); dauerte: 618ms - 2213706 Ticks
1000000 x result = (p.FirstName + "" + p.LastName); dauerte: 166ms - 595610 Zecken
string.Format
, das keine zusammengesetzten Formatierungsfunktionen verwendet (dh einfach{0}
) und diese durch die erheblich schnellere Verkettung von Zeichenfolgen ersetzt. Ich frage mich, ob eine solche Leistung mit einem vorhandenen IL-Umschreiber wie PostSharp erreichbar ist.Ich bin erstaunt, dass so viele Leute sofort den Code finden möchten, der am schnellsten ausgeführt wird. Wenn die Verarbeitung von EINER MILLION Iterationen NOCH weniger als eine Sekunde dauert, wird dies für den Endbenutzer in irgendeiner Weise erkennbar sein? Nicht sehr wahrscheinlich.
Ich würde mich für diese
String.Format
Option entscheiden, nur weil sie aus architektonischer Sicht am sinnvollsten ist. Die Leistung ist mir erst wichtig, wenn sie zu einem Problem wird (und wenn ja, würde ich mich fragen: Muss ich eine Million Namen gleichzeitig verketten? Sicherlich passen nicht alle auf den Bildschirm ...)Überlegen Sie, ob Ihr Kunde es später ändern möchte, damit er konfigurieren kann, ob
"Firstname Lastname"
oder"Lastname, Firstname."
mit der Option Format angezeigt werden soll. Dies ist einfach - tauschen Sie einfach die Formatzeichenfolge aus. Mit dem Concat benötigen Sie zusätzlichen Code. Sicher, das klingt in diesem Beispiel nicht nach einer großen Sache, sondern extrapoliert.quelle
Oh je - nachdem ich eine der anderen Antworten gelesen hatte, versuchte ich, die Reihenfolge der Operationen umzukehren - also führte ich zuerst die Verkettung durch, dann das String.Format ...
Die Reihenfolge der Operationen macht also einen RIESIGEN Unterschied, oder vielmehr ist die allererste Operation IMMER viel langsamer.
Hier sind die Ergebnisse eines Laufs, bei dem Vorgänge mehr als einmal ausgeführt wurden. Ich habe versucht, die Reihenfolge zu ändern, aber die Dinge folgen im Allgemeinen den gleichen Regeln, sobald das erste Ergebnis ignoriert wird:
Wie Sie sehen können, sind nachfolgende Läufe derselben Methode (ich habe den Code in 3 Methoden umgestaltet) inkrementell schneller. Die schnellste Methode scheint die Console.WriteLine-Methode (String.Concat (...)) zu sein, gefolgt von der normalen Verkettung und den formatierten Vorgängen.
Die anfängliche Verzögerung beim Start ist wahrscheinlich die Initialisierung von Console Stream, da eine Console.Writeline ("Start!") Vor dem ersten Vorgang alle Zeiten wieder in Einklang bringt.
quelle
Zeichenfolgen sind unveränderlich. Dies bedeutet, dass in Ihrem Code immer wieder dasselbe kleine Stück Speicher verwendet wird. Das Hinzufügen derselben zwei Zeichenfolgen und das wiederholte Erstellen derselben neuen Zeichenfolge wirkt sich nicht auf den Speicher aus. .Net ist intelligent genug, um nur dieselbe Speicherreferenz zu verwenden. Daher testet Ihr Code den Unterschied zwischen den beiden Concat-Methoden nicht wirklich.
Probieren Sie dies für die Größe an:
Beispielausgabe:
quelle
string.Format
den winzigen Leistungseinbruch hier wert ist. Architektonisch ist es besser, da Sie das Format einfacher ändern können. Aber Stringbuilder verstehe ich wirklich nicht. Jeder andere Thread hier sagt, dass Sie Stringbuilder verwenden sollten, anstatt Zeichenfolgen zu verketten. Was ist der Vorteil? Ganz klar keine Geschwindigkeit, wie dieser Benchmark beweist.Schade um die armen Übersetzer
Wenn Sie wissen, dass Ihre Bewerbung auf Englisch bleibt, speichern Sie die Uhr-Ticks. In vielen Kulturen wird jedoch normalerweise der Nachname Vorname beispielsweise in Adressen angezeigt.
Verwenden
string.Format()
Sie diese Option, insbesondere wenn Ihre Anwendung jemals irgendwohin gehen soll, wo Englisch nicht die erste Sprache ist.quelle
string.Format()
sich in verschiedenen Kulturen unterschiedlich verhalten? Würde es nicht immer noch den Vor- und Nachnamen drucken? Es scheint, als müssten Sie in beiden Situationen die unterschiedliche Kultur berücksichtigen. Ich habe das Gefühl, dass mir hier etwas fehlt.string.Format()
wissen Sie, dass Sie einen Namen für eine Adresse verwenden? Wenn ich aufgrund der Kulturstring.Format()
getauscht{0} {1}
würde, würde ich es als kaputt betrachten.Hier sind meine Ergebnisse über 100.000 Iterationen:
Und hier ist der Bankcode:
Also, ich weiß nicht, wessen Antwort als Antwort zu markieren ist :)
quelle
Das Verketten von Zeichenfolgen ist in einem einfachen Szenario wie diesem in Ordnung - es ist komplizierter mit etwas Komplizierterem als diesem, sogar Nachname, Vorname. Mit dem Format können Sie auf einen Blick sehen, wie die endgültige Struktur der Zeichenfolge beim Lesen des Codes aussehen wird. Bei Verkettung ist es fast unmöglich, das Endergebnis sofort zu erkennen (außer bei einem sehr einfachen Beispiel wie diesem).
Auf lange Sicht bedeutet dies, dass Sie, wenn Sie zurückkommen, um Änderungen an Ihrem Zeichenfolgenformat vorzunehmen, entweder die Möglichkeit haben, die Formatzeichenfolge zu ändern oder ein paar Anpassungen vorzunehmen, oder die Stirn runzeln und sich bewegen können Arten von Eigenschaftszugängern, die mit Text gemischt sind, was eher zu Problemen führt.
Wenn Sie .NET 3.5 verwenden, können Sie eine Erweiterungsmethode wie diese verwenden und einen einfachen Ablauf erzielen, der von der Manschettensyntax wie folgt abweicht:
Wenn Ihre Anwendung immer komplexer wird, können Sie entscheiden, dass Sie Zeichenfolgen in Ihrer Anwendung in eine Ressourcendatei verschieben möchten, um sie zu lokalisieren, oder einfach in einen statischen Helfer, um sie ordnungsgemäß zu verwalten. Dies ist VIEL einfacher zu erreichen, wenn Sie konsequent Formate verwendet haben, und Ihr Code kann ganz einfach überarbeitet werden, um so etwas zu verwenden
quelle
Für eine sehr einfache Manipulation würde ich die Verkettung verwenden, aber sobald Sie über 2 oder 3 Elemente hinaus sind, wird das Format IMO geeigneter.
Ein weiterer Grund, String.Format zu bevorzugen, besteht darin, dass .NET-Zeichenfolgen unveränderlich sind und auf diese Weise weniger temporäre / Zwischenkopien erstellt werden.
quelle
Während ich die Stilpräferenz vollständig verstehe und die Verkettung für meine erste Antwort teilweise basierend auf meiner eigenen Präferenz ausgewählt habe, basierte ein Teil meiner Entscheidung auf dem Gedanken, dass die Verkettung schneller sein würde. Aus Neugier habe ich es getestet und die Ergebnisse waren atemberaubend, besonders für eine so kleine Saite.
Verwenden Sie den folgenden Code:
Ich habe folgende Ergebnisse erhalten:
Die Formatierungsmethode ist über 100-mal langsamer !! Die Verkettung wurde nicht einmal als 1 ms registriert, weshalb ich auch die Timer-Ticks ausgab.
quelle
Ab C # 6.0 können interpolierte Zeichenfolgen verwendet werden, was das Format noch weiter vereinfacht.
Interpolierte Zeichenfolgen weisen eine ähnliche Leistung wie String.Format auf, verbessern jedoch die Lesbarkeit und die kürzere Syntax, da Werte und Ausdrücke in Zeile eingefügt werden.
Bitte lesen Sie auch diesen dotnetperls-Artikel zur String-Interpolation.
Wenn Sie nach einer Standardmethode zum Formatieren Ihrer Zeichenfolgen suchen, ist dies in Bezug auf Lesbarkeit und Leistung sinnvoll (außer wenn Mikrosekunden in Ihrem speziellen Anwendungsfall einen Unterschied machen).
quelle
Für die grundlegende Verkettung von Zeichenfolgen verwende ich im Allgemeinen den zweiten Stil - einfacher zu lesen und einfacher. Wenn ich jedoch eine kompliziertere String-Kombination mache, entscheide ich mich normalerweise für String.Format.
String.Format spart viele Anführungszeichen und Pluspunkte ...
Nur ein paar Zeichen gespeichert, aber ich denke, in diesem Beispiel macht das Format es viel sauberer.
quelle
Ein besserer Test wäre, Ihren Speicher mit Perfmon und den CLR-Speicherzählern zu überwachen. Meines Wissens nach ist der ganze Grund, warum Sie String.Format verwenden möchten, anstatt nur Strings zu verketten, dass Sie den Garbage Collector unnötig mit temporären Strings belasten, die im nächsten Durchgang zurückgefordert werden müssen, da Strings unveränderlich sind.
StringBuilder und String.Format sind zwar möglicherweise langsamer, aber speichereffizienter.
Was ist so schlimm an der Verkettung von Zeichenfolgen?
quelle
Im Allgemeinen bevorzuge ich Ersteres, da es viel einfacher zu lesen ist, wenn die Saiten lang werden.
Der andere Vorteil ist meiner Meinung nach die Leistung, da letztere tatsächlich zwei Anweisungen zum Erstellen von Zeichenfolgen ausführt, bevor die endgültige Zeichenfolge an die Console.Write-Methode übergeben wird. String.Format verwendet meines Erachtens einen StringBuilder unter dem Deckmantel, sodass mehrfache Verkettungen vermieden werden.
Es sollte jedoch beachtet werden, dass die Parameter, die Sie an String.Format übergeben (und andere Methoden wie Console.Write), Werttypen sind, die vor der Übergabe eingerahmt werden, was zu eigenen Leistungstreffern führen kann. Blogbeitrag dazu hier .
quelle
In einer Woche, dem 19. August 2015, wird diese Frage genau sieben (7) Jahre alt sein. Es gibt jetzt einen besseren Weg, dies zu tun. Besser in Bezug auf die Wartbarkeit, da ich keinen Leistungstest durchgeführt habe, als nur Zeichenfolgen zu verketten (aber spielt es heutzutage eine Rolle? Ein paar Millisekunden Unterschied?). Die neue Methode mit C # 6.0 :
Diese neue Funktion ist besser , IMO und in unserem Fall sogar besser, da wir Codes haben, in denen wir Querystringe erstellen, deren Werte von einigen Faktoren abhängen. Stellen Sie sich einen Querystring vor, bei dem wir 6 Argumente haben. Also anstatt zum Beispiel:
in kann so geschrieben werden und ist leichter zu lesen:
quelle
quelle
Ich würde die Zeichenfolge String.Format verwenden, aber ich hätte auch die Formatzeichenfolge in den Ressourcendateien, damit sie für andere Sprachen lokalisiert werden kann. Mit einem einfachen String-Concat können Sie das nicht tun. Wenn Sie diese Zeichenfolge nie lokalisieren müssen, ist dies natürlich kein Grund zum Nachdenken. Es kommt wirklich darauf an, wofür der String ist.
Wenn es dem Benutzer angezeigt wird, würde ich String.Format verwenden, damit ich es lokalisieren kann, wenn ich muss - und FxCop wird es für mich überprüfen, nur für den Fall :)
Wenn es Zahlen oder andere Dinge enthält, die keine Zeichenfolgen sind (z. B. Datumsangaben), würde ich String.Format verwenden, da ich dadurch mehr Kontrolle über die Formatierung habe .
Wenn es darum geht, eine Abfrage wie SQL zu erstellen , würde ich Linq verwenden .
Wenn Sie Zeichenfolgen innerhalb einer Schleife verketten möchten, würde ich StringBuilder verwenden , um Leistungsprobleme zu vermeiden.
Wenn es sich um eine Ausgabe handelt, die der Benutzer nicht sieht und die Leistung nicht beeinträchtigt, würde ich String.Format verwenden, da ich es sowieso gewohnt bin und es nur gewohnt bin :)
quelle
Wenn Sie mit etwas zu tun haben, das einfach zu lesen sein muss (und dies ist der meiste Code), würde ich mich an die Operator-Überlastungsversion halten, AUSSER:
Unter mindestens zwei dieser Umstände würde ich stattdessen StringBuilder verwenden.
quelle
Ich wähle basierend auf der Lesbarkeit. Ich bevorzuge die Formatierungsoption, wenn die Variablen Text enthalten. In diesem Beispiel:
Sie verstehen die Bedeutung auch ohne Variablennamen, während der Concat mit Anführungszeichen und + Zeichen überfüllt ist und meine Augen verwirrt:
(Ich habe Mikes Beispiel ausgeliehen, weil es mir gefällt)
Wenn die Formatzeichenfolge ohne Variablennamen nicht viel bedeutet, muss ich concat verwenden:
Mit der Formatoption kann ich die Variablennamen lesen und sie den entsprechenden Nummern zuordnen. Die concat-Option erfordert das nicht. Ich bin immer noch verwirrt von den Anführungszeichen und + Zeichen, aber die Alternative ist schlimmer. Rubin?
Performance weise erwarte ich, dass die Formatoption langsamer sein dann die Concat, da Format die Zeichenfolge erfordert werden analysiert . Ich erinnere mich nicht, dass ich diese Art von Unterricht optimieren musste, aber wenn ich das tat, würde ich mir
string
Methoden wieConcat()
und ansehenJoin()
.Der andere Vorteil des Formats besteht darin, dass die Formatzeichenfolge in eine Konfigurationsdatei eingefügt werden kann. Sehr praktisch mit Fehlermeldungen und UI-Text.
quelle
Wenn Sie das Ergebnis lokalisieren möchten, ist String.Format unerlässlich, da in verschiedenen natürlichen Sprachen die Daten möglicherweise nicht in derselben Reihenfolge vorliegen.
quelle
Ich denke, das hängt stark davon ab, wie komplex die Ausgabe ist. Ich neige dazu, das Szenario zu wählen, das zu der Zeit am besten funktioniert.
Wählen Sie das richtige Werkzeug für den Job: D Was am saubersten aussieht!
quelle
Ich bevorzuge auch die zweite, aber ich habe derzeit keine rationalen Argumente, um diese Position zu unterstützen.
quelle
Schön!
Gerade hinzugefügt
Und es ist noch schneller (ich denke string.Concat wird in beiden Beispielen aufgerufen, aber das erste erfordert eine Art Übersetzung).
quelle
string.Concat(...)
. Es wird während der Kompilierung durchgeführt, sodass es keinen Einfluss auf die Laufzeitleistung hat. Wenn Sie Ihre Tests mehrmals ausführen oder sie an größeren Testmustern ausführen, werden Sie feststellen, dass sie identisch sind.Da ich nicht denke, dass die Antworten hier alles abdecken, möchte ich hier eine kleine Ergänzung machen.
Console.WriteLine(string format, params object[] pars)
Anrufestring.Format
. Das '+' impliziert eine Verkettung von Zeichenfolgen. Ich denke nicht, dass dies immer mit Stil zu tun hat. Ich neige dazu, die beiden Stile zu mischen, je nachdem, in welchem Kontext ich mich befinde.Kurze Antwort
Die Entscheidung, vor der Sie stehen, hängt mit der Zuweisung von Zeichenfolgen zusammen. Ich werde versuchen, es einfach zu machen.
Sagen Sie, Sie haben
Wenn Sie dies ausführen, wird Folgendes ausgewertet:
tmp
Hier handelt es sich nicht wirklich um eine lokale Variable, sondern um eine temporäre Variable für die JIT (sie wird auf den IL-Stack übertragen). Wenn Sie eine Zeichenfolge auf den Stapel schieben (zldstr
in IL für Literale), setzen Sie einen Verweis auf einen Zeichenfolgenzeiger auf dem Stapel.In dem Moment, in dem Sie anrufen
concat
diese Referenz wird zu einem Problem, da keine Zeichenfolgenreferenz verfügbar ist, die beide Zeichenfolgen enthält. Dies bedeutet, dass .NET einen neuen Speicherblock zuweisen und ihn dann mit den beiden Zeichenfolgen füllen muss. Der Grund dafür ist, dass die Zuweisung relativ teuer ist.Was die Frage ändert zu: Wie können Sie die Anzahl der reduzieren
concat
Operationen ?Die grobe Antwort lautet also:
string.Format
Für> 1 Concat funktioniert '+' für 1 Concat einwandfrei. Und wenn Sie sich nicht für die Optimierung der Mikroleistung interessieren,string.Format
funktioniert dies im allgemeinen Fall einwandfrei.Ein Hinweis zur Kultur
Und dann gibt es so etwas wie Kultur ...
string.Format
ermöglicht es Ihnen,CultureInfo
in Ihrer Formatierung zu verwenden. Ein einfacher Operator '+' verwendet die aktuelle Kultur.Dies ist besonders wichtig, wenn Sie Dateiformate und f.ex schreiben.
double
Werte, die Sie einer Zeichenfolge hinzufügen. Auf verschiedenen Computern werden möglicherweise unterschiedliche Zeichenfolgen angezeigt, wenn Sie keinestring.Format
explizite Zeichenfolge verwendenCultureInfo
.F.ex. Überlegen Sie, was passiert, wenn Sie ein '.' ändern. Für ein ',' beim Schreiben Ihrer Datei mit durch Kommas getrennten Werten ... auf Niederländisch ist das Dezimaltrennzeichen ein Komma, sodass Ihr Benutzer möglicherweise nur eine 'lustige' Überraschung erhält.
Weitere detaillierte Antwort
Wenn Sie die genaue Größe der Zeichenfolge vorher nicht kennen, verwenden Sie am besten eine solche Richtlinie, um die von Ihnen verwendeten Puffer zu ordnen. Der Leerraum wird zuerst gefüllt, wonach die Daten kopiert werden.
Wachsen bedeutet, einen neuen Speicherblock zuzuweisen und die alten Daten in den neuen Puffer zu kopieren. Der alte Speicherblock kann dann freigegeben werden. An diesem Punkt erhalten Sie das Endergebnis: Wachsen ist eine teure Operation.
Der praktischste Weg, dies zu tun, ist die Verwendung einer Gesamtzuordnungsrichtlinie. Die gebräuchlichste Richtlinie besteht darin, Puffer mit einer Potenz von 2 zuzuweisen. Natürlich müssen Sie dies etwas intelligenter tun (da es keinen Sinn macht, von 1,2,4,8 zu wachsen, wenn Sie bereits wissen, dass Sie 128 Zeichen benötigen ) aber du bekommst das Bild. Die Richtlinie stellt sicher, dass Sie nicht zu viele der oben beschriebenen teuren Vorgänge benötigen.
StringBuilder
ist eine Klasse, die den zugrunde liegenden Puffer grundsätzlich in Zweierpotenzen zusammenfasst.string.Format
verwendetStringBuilder
unter der Haube.Dies macht Ihre Entscheidung zu einem grundlegenden Kompromiss zwischen Gesamtzuweisung und Anhängen (-mehrfach) (ohne Kultur) oder einfach Zuweisung und Anhängen.
quelle
Persönlich ist die zweite, da alles, was Sie verwenden, in der direkten Reihenfolge, in der sie ausgegeben wird. Während Sie bei der ersten die Werte {0} und {1} mit der richtigen Var abgleichen müssen, was leicht zu vermasseln ist.
Zumindest ist es nicht so schlimm wie das C ++ - Sprintf, bei dem das Ganze explodiert, wenn der Variablentyp falsch ist.
Da die zweite inline ist und nicht nach allen {0} Dingen gesucht und ersetzt werden muss, sollte letztere schneller sein ... obwohl ich es nicht genau weiß.
quelle
Eigentlich mag ich die erste, weil es mir einfacher erscheint, wenn viele Variablen mit dem Text vermischt sind. Außerdem ist es einfacher, mit Anführungszeichen umzugehen, wenn Sie das Format string.Format () verwenden. Hier ist eine anständige Analyse der String-Verkettung.
quelle
Ich bin immer die string.Format () -Route gegangen. Die Möglichkeit, Formate in Variablen wie Nathans Beispiel zu speichern, ist ein großer Vorteil. In einigen Fällen kann ich eine Variable anhängen, aber sobald mehr als eine Variable verkettet ist, überarbeite ich die Formatierung.
quelle
Oh, und der Vollständigkeit halber ist das Folgende ein paar Ticks schneller als die normale Verkettung:
quelle
Das erste (Format) sieht für mich besser aus. Es ist besser lesbar und Sie erstellen keine zusätzlichen temporären Zeichenfolgenobjekte.
quelle
Ich war neugierig, wo StringBuilder mit diesen Tests stand. Ergebnisse unten ...
Ergebnisse:
quelle
Laut dem MCSD-Vorbereitungsmaterial schlägt Microsoft vor, den Operator + zu verwenden, wenn eine sehr kleine Anzahl von Verkettungen (wahrscheinlich 2 bis 4) behandelt wird. Ich bin mir immer noch nicht sicher warum, aber es ist etwas zu beachten.
quelle