Was ist der effizienteste Weg, um Zeichenfolgen zu verketten?
c#
.net
string
optimization
jimmij
quelle
quelle
StringBuilder
Anwendungsfällen finden Sie hier .String.Format
bei Steroiden. Welche, Leistung klug, ist ein winzig bisschen langsamer an einem Liner als+
undString.Concat
, aber viel besser als die, wenn auch langsamer alsStringBuilder
bei mehreren Anrufen. In der Praxis sind die Leistungsunterschiede so groß, dass ich, wenn ich nur einen Weg zum Verketten wählen müsste, String-Interpolationen mit$
... Wenn zwei Wege wählen würde , dann fügeStringBuilder
sie meiner Toolbox hinzu. Mit diesen beiden Möglichkeiten sind Sie eingestellt.String.Join
Antwort wird nicht+
gerecht und ist praktisch eine schlechte Methode, um Zeichenfolgen zu verketten, aber in Bezug auf die Leistung ist sie überraschend schnell. Die Antwort warum ist interessant.String.Concat
undString.Join
kann beide auf Arrays wirken, ist aberString.Join
tatsächlich schneller. AnscheinendString.Join
ist es ziemlich ausgefeilt und optimierter alsString.Concat
, teilweise weil es ähnlich funktioniert,StringBuilder
indem es zuerst die Stringlänge berechnet und dann den String erstellt, der von diesem Wissen profitiert, indem es UnSafeCharBuffer verwendet.String.Join
erfordert auch eine Reihe konstruieren , die Ressource ineffizient Recht scheint? ... Es stellte sich heraus , dass+
undString.Concat
Konstrukt - Arrays für ihre Bestandteile sowieso. Folglich ist das manuelle Erstellen und Zuführen eines ArraysString.Join
vergleichsweise schneller. EsStringBuilder
übertrifft jedochString.Join
in nahezu jeder praktischen Hinsicht, während$
es bei langen Zeichenfolgen nur geringfügig langsamer und viel schneller ist. Ganz zu schweigen davon, dass die Verwendung umständlich und hässlich ist,String.Join
wenn Sie dies getan haben um vor Ort ein Array dafür zu erstellen.Antworten:
Die
StringBuilder.Append()
Methode ist viel besser als die Verwendung des+
Operators. Aber ich habe festgestellt, dass es bei der Ausführung von 1000 Verkettungen oder wenigerString.Join()
noch effizienter ist alsStringBuilder
.Das einzige Problem dabei
String.Join
ist, dass Sie die Zeichenfolgen mit einem gemeinsamen Trennzeichen verketten müssen.Bearbeiten: Wie @ryanversaw betonte, können Sie das Trennzeichen festlegen
string.Empty
.quelle
StringBuilder
hat enorme vergleichbare Startkosten und ist nur dann effizient, wenn es mit sehr großen Zeichenfolgen oder sehr vielen Verkettungen verwendet wird. Es ist nicht trivial, dies für eine bestimmte Situation herauszufinden. Wenn die Leistung ein Problem darstellt, ist die Profilerstellung Ihr Freund (siehe ANTS).string.Concat
?Rico Mariani , der .NET Performance Guru, hatte einen Artikel zu diesem Thema. Es ist nicht so einfach, wie man vermuten könnte. Der grundlegende Rat lautet:
Ein weiterer Artikel zur Unterstützung dieser Behauptung stammt von Eric Lippert, in dem er die Optimierungen, die für
+
Verkettungen in einer Zeile durchgeführt wurden, ausführlich beschreibt.quelle
Es gibt 6 Arten von Zeichenfolgenverkettungen:
+
).string.Concat()
.string.Join()
.string.Format()
.string.Append()
.StringBuilder
.In einem Experiment wurde dies bewiesen
string.Concat()
der beste Weg ist, wenn die Wörter weniger als 1000 (ungefähr) sind und wenn die Wörter mehr als 1000 sind, dannStringBuilder
sollte verwendet werden.Weitere Informationen finden Sie auf dieser Website .
quelle
+
das tatsächlich 3 Millisekunden schneller war alsstring.Concat()
, obwohl ich nicht die Anzahl der vorstring.Concat()
Outraces erforderlichen Zeichenfolgen untersucht habe+
.Von Chinh Do - StringBuilder ist nicht immer schneller :
Faustregeln
Bei der Verkettung von dreiVerwenden Sie dynamischen Zeichenfolgenwerten oder weniger die herkömmliche Zeichenfolgenverkettung.
Verwenden Sie, wenn Sie mehr als drei dynamische Zeichenfolgenwerte verketten
StringBuilder
.Verwenden Sie beim Erstellen einer großen Zeichenfolge aus mehreren Zeichenfolgenliteralen entweder das
@
Zeichenfolgenliteral oder den Inline + -Operator.Die meiste Zeit
StringBuilder
ist Ihre beste Wahl, aber es gibt Fälle, wie in diesem Beitrag gezeigt, in denen Sie zumindest über jede Situation nachdenken sollten.quelle
Wenn Sie in einer Schleife arbeiten,
StringBuilder
ist dies wahrscheinlich der richtige Weg. Dies erspart Ihnen den Aufwand, regelmäßig neue Zeichenfolgen zu erstellen. In Code, der nur einmal ausgeführt wird,String.Concat
ist dies wahrscheinlich in Ordnung.Rico Mariani (.NET-Optimierungsguru) hat jedoch ein Quiz zusammengestellt, in dem er am Ende erklärte, dass er in den meisten Fällen empfiehlt
String.Format
.quelle
Hier ist die schnellste Methode, die ich in einem Jahrzehnt für meine große NLP-App entwickelt habe. Ich habe Variationen für
IEnumerable<T>
und andere Eingabetypen mit und ohne Trennzeichen unterschiedlicher Typen (Char
,String
), aber hier zeige ich den einfachen Fall, dass alle Zeichenfolgen in einem Array zu einer einzelnen Zeichenfolge ohne Trennzeichen verkettet werden . Die neueste Version hier wurde unter C # 7 und .NET 4.7 entwickelt und getestet .Es gibt zwei Schlüssel für eine höhere Leistung. Die erste besteht darin, die genaue erforderliche Gesamtgröße vorab zu berechnen. Dieser Schritt ist trivial, wenn die Eingabe ein Array ist, wie hier gezeigt. Für die Behandlung
IEnumerable<T>
lohnt es sich, zuerst die Zeichenfolgen in einem temporären Array zu sammeln, um diese Summe zu berechnen (das Array ist erforderlich, um einen Aufruf zu vermeidenToString()
mehr als einmal pro Element da dies technisch gesehen die Möglichkeit einer möglichen Änderung der erwarteten Semantik haben könnte einer 'String Join'-Operation).Angesichts der Gesamtzuordnungsgröße der endgültigen Zeichenfolge wird der größte Leistungsschub erzielt, wenn die Ergebniszeichenfolge direkt erstellt wird . Dies erfordert die (möglicherweise umstrittene) Technik, die Unveränderlichkeit eines neuen,
String
der zunächst mit Nullen versehen ist, vorübergehend auszusetzen . Abgesehen von solchen Kontroversen ...Vollständiger Code:
Ich sollte erwähnen, dass dieser Code eine geringfügige Änderung gegenüber dem aufweist, was ich selbst verwende. Im Original rufe ich die Anweisung cpblk IL von C # auf, um das eigentliche Kopieren durchzuführen . Zur Vereinfachung und Portabilität des Codes hier habe ich diesen
memcpy
stattdessen durch P / Invoke ersetzt , wie Sie sehen können. Für höchste Leistung unter x64 ( aber möglicherweise nicht unter x86 ) möchten Sie möglicherweise stattdessen die cpblk- Methode verwenden.quelle
string.Join
erledigt all diese Dinge bereits für Sie. Sie müssen es nicht selbst schreiben. Es berechnet die Größe der endgültigen Zeichenfolge, erstellt eine Zeichenfolge dieser Größe und schreibt dann in das zugrunde liegende Zeichenarray. Es hat sogar den Vorteil, dass dabei lesbare Variablennamen verwendet werden.String.Join
kann effizient sein. Wie ich im Intro angedeutet habe, ist der Code hier nur die einfachste Darstellung einer Funktionsfamilie, die ich für Szenarien verwende, dieString.Join
entweder nicht (z. B. Optimierung fürChar
Trennzeichen) oder in früheren Versionen von .NET nicht verarbeitet wurden. Ich nehme an, ich hätte dies nicht für das einfachste Beispiel auswählen sollen, da es sich um einen Fall handelt, derString.Join
bereits gut funktioniert, wenn auch mit der "Ineffizienz", die wahrscheinlich nicht messbar ist, nämlich die Verarbeitung eines leeren Trennzeichens, nämlich.String.Empty
.Concat
, die auch dies richtig funktionieren. In beiden Fällen müssen Sie den Code nicht selbst schreiben.String.Join
meinem Code unter Verwendung dieses Testkabels verglichen . Bei 10 Millionen zufälligen Verkettungsvorgängen mit jeweils bis zu 100 Zeichenfolgen in Wortgröße ist der oben gezeigte Code durchweg 34% schneller alsString.Join
bei der Erstellung von x64- Versionen mit .NET 4.7 . Da das OP ausdrücklich die "effizienteste" Methode anfordert, deutet das Ergebnis darauf hin, dass meine Antwort zutrifft. Wenn dies Ihre Bedenken anspricht, lade ich Sie ein, Ihre Ablehnung zu überdenken.Aus diesem MSDN-Artikel :
Wenn Sie also MSDN vertrauen, gehen Sie mit StringBuilder, wenn Sie mehr als 10 Zeichenfolgenoperationen / -verkettungen ausführen müssen - andernfalls ist eine einfache Zeichenfolgenübereinstimmung mit '+' in Ordnung.
quelle
Es ist auch wichtig darauf hinzuweisen, dass Sie den
+
Operator verwenden sollten, wenn Sie Zeichenfolgenliterale verketten .Gewusst wie: Verketten mehrerer Zeichenfolgen (C # -Programmierhandbuch)
quelle
Beachten Sie, dass StringBuilder zusätzlich zu den anderen Antworten eine anfängliche Speichermenge zugewiesen werden kann .
Das wiederholte Anhängen an einen nicht vorab zugewiesenen StringBuilder kann zu vielen unnötigen Zuweisungen führen, ebenso wie das wiederholte Verketten regulärer Zeichenfolgen.
Wenn Sie wissen, wie lang die endgültige Zeichenfolge sein wird, sie trivial berechnen oder eine fundierte Vermutung über den allgemeinen Fall anstellen können (zu viel zuzuweisen ist nicht unbedingt eine schlechte Sache), sollten Sie diese Informationen dem Konstruktor oder dem Kapazitätseigenschaft . Insbesondere beim Ausführen von Leistungstests, um StringBuilder mit anderen Methoden wie String.Concat zu vergleichen, die intern dasselbe tun. Jeder Test, den Sie online sehen und der keine StringBuilder-Vorzuweisung in seine Vergleiche einbezieht, ist falsch.
Wenn Sie keine Vermutung über die Größe anstellen können, schreiben Sie wahrscheinlich eine Dienstprogrammfunktion, die über ein eigenes optionales Argument zur Steuerung der Vorzuweisung verfügen sollte.
quelle
Das Folgende kann eine weitere alternative Lösung sein, um mehrere Zeichenfolgen zu verketten.
String-Interpolation
quelle
String.Format
aber besser lesbar und einfacher zu bearbeiten. Beim Benchmarking ist es etwas langsamer als+
undString.Concat
bei Verkettungen in einer Zeile, aber viel besser als bei wiederholten Anrufen, wasStringBuilder
weniger notwendig macht.Am effizientesten ist es, StringBuilder wie folgt zu verwenden:
@jonezy: String.Concat ist in Ordnung, wenn Sie ein paar kleine Dinge haben. Wenn Sie jedoch Megabyte an Daten verketten, wird Ihr Programm wahrscheinlich tanken.
quelle
Probieren Sie diese 2 Codeteile aus und Sie werden die Lösung finden.
Vs
Sie werden feststellen, dass der erste Code sehr schnell endet und der Speicher in einer guten Menge vorhanden ist.
Der zweite Code ist vielleicht in Ordnung, aber es wird länger dauern ... viel länger. Wenn Sie also eine Anwendung für viele Benutzer haben und Geschwindigkeit benötigen, verwenden Sie die erste. Wenn Sie eine App für eine kurzfristige Ein-Benutzer-App haben, können Sie möglicherweise beide verwenden, oder die zweite ist für Entwickler "natürlicher".
Prost.
quelle
Für nur zwei Zeichenfolgen möchten Sie StringBuilder definitiv nicht verwenden. Es gibt einen Schwellenwert, oberhalb dessen der StringBuilder-Overhead geringer ist als der Overhead beim Zuweisen mehrerer Strings.
Verwenden Sie für mehr als 2-3 Zeichenfolgen den Code von DannySmurf . Verwenden Sie andernfalls einfach den Operator +.
quelle
System.String ist unveränderlich. Wenn wir den Wert einer Zeichenfolgenvariablen ändern, wird dem neuen Wert ein neuer Speicher zugewiesen und die vorherige Speicherzuordnung freigegeben. System.StringBuilder wurde für das Konzept einer veränderlichen Zeichenfolge entwickelt, bei der eine Vielzahl von Operationen ausgeführt werden können, ohne dass der geänderten Zeichenfolge ein separater Speicherort zugewiesen werden muss.
quelle
Eine andere Lösung:
Verwenden Sie innerhalb der Schleife List anstelle von String.
es ist sehr sehr schnell.
quelle
Es hängt wirklich von Ihrem Nutzungsmuster ab. Einen detaillierten Benchmark zwischen string.Join, string, Concat und string.Format finden Sie hier: String.Format ist nicht für die intensive Protokollierung geeignet
(Dies ist eigentlich die gleiche Antwort, die ich auf diese Frage gegeben habe)
quelle
Es würde vom Code abhängen. StringBuilder ist im Allgemeinen effizienter, aber wenn Sie nur ein paar Zeichenfolgen verketten und alles in einer Zeile erledigen, werden Code-Optimierungen dies wahrscheinlich für Sie erledigen. Es ist wichtig, darüber nachzudenken, wie der Code auch aussieht: Bei größeren Mengen erleichtert StringBuilder das Lesen, bei kleinen fügt StringBuilder nur unnötige Unordnung hinzu.
quelle