Entwickler-Ecke
Basistechnologien - Speichermanagement StringBuilder und StreamWriter
Nuckey - Sa 14.04.12 13:19
Titel: Speichermanagement StringBuilder und StreamWriter
zur zeit schwirt ein problem/frage in meinem kopf rum.
wenn ich mit stringbuilder arbeite nimmt dieser je nach grösse der strings speicher in anspruch,
ebenso StreamWriter (glaube von 1024byte).
was wäre speicher schonender:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| StringBuilder sb = new StringBuilder(); sb.append("hallo"); . viele strings . sb.append("welt");
StreamWriter sw .... sw.Writeline(sb.tostring());
sw.writeline("hallo"); . viele strings . sw.writeline("welt"); |
mit viele strings meinte ich,das da nicht nur mit 2 stringketten gearbeitet wird zb. mit 20.
ist es "wirtschaftlicher" von einem buffer in dehn anderen zu schreiben oder
direkt ?.
mfg nuckey
Moderiert von
Th69: Code- durch C#-Tags ersetzt
Ralf Jansen - Sa 14.04.12 13:59
Von deinem Casing und Methodenbezeichnung her soll, das wirklich C# sein oder eher Java?
In .Net hat ein Stringbuilder eine DefaultKapazität von 16 Chars (nicht zu verwechseln mit 16 Byte) und verdoppelt die Größe bei Bedarf.
Wenn du nach Wirtschaftlichkeit fragst müsste ich antworten die Version du du schneller fehlerfrei entwickeln kannst. Der eventuelle Unterschied in der Ausführungsgeschwindigkeit ist in 99,99% aller Anwendungsfälle kosten technisch vernachlässigbar gegenüber den Entwicklungskosten.
Wenn die Frage auf die Ausführungsgeschwindigkeit abzielte würde ich die erste Version vorziehen da ich die Geschwindigkeit für vorhersagbarer halte. Bei der direkte Nutzung des Streamwriters kommt es auf das genaue Verhalten des dahinterliegenden Streams an. Wie oft zwischendurch vom Streamwriter geflusht wird und wie performant der Flush ist. Wenn du den StringBuilder schon mit passender Kapazität initialisiert hast bleiben als die zwei treibenden Kostenfaktoren nur der ToString und das nur einmalige flushen über den Streamwriter. Das unter der Annahme das StringBuilder.Append und StreamWriter.Write (ohne einen eventuellen Flush in Write) etwa gleich schnell sein werden.
Th69 - Sa 14.04.12 14:00
Hallo Nuckey,
bei dem StreamWriter ist es eigentlich unsinnig, zuerst einen StringBuilder zu benutzen, um daraus dann einen String zu erzeugen, welcher dann gestreamt wird.
Sinn könnte dies höchstens machen, wenn man eine externe Methode verwendet, welche den Inhalt erzeugen soll. Dann würde man wohl besser einen String zurückgeben, anstatt direkt in einen Stream zu schreiben (damit diese Methode allgemeingültig bleibt).
Nuckey - Sa 14.04.12 17:19
danke erstmal:
nein ralf es ist nicht java, eher pseudo-pseudo c#++ ;)
es ist so das ich bisher die felser ausgelesenhabe und dies in einem string per stringbuilder gepacckt habe
und diese den per stream geschrieben habe.
beispiel
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50:
| public class Klasse stringbuilder sb = new stringbuilder
public ToString() { sb.Clear(); sb.AppendLine("newBlueprint = {");
if (!S2EdParseCtrl.IsString(this._s2ObjectInfo)) sb.AppendFormat("--# {0}\r\n", this._s2ObjectInfo);
sb.AppendFormat(" id = {0},\r\n", this._s2ObjectId); sb.AppendFormat(" name = \"{0}\",\r\n", this._s2ObjectName); sb.AppendFormat(" palettebits = \"{0}\",\r\n", this._palettebits); sb.AppendFormat(" dmgvariation = {0},\r\n", this._dmgvariation); sb.Append(this.MinConStraints.ToString()); sb.AppendFormat(" lvljump = {0},\r\n", this._lvljump); sb.AppendFormat(" usability = {0},\r\n", this._usability); sb.Append(this.AllotmentPmfpi.ToString());
if (!S2EdParseCtrl.IsString(this._unicname)) sb.AppendFormat(" uniquename = \"{0}\",\r\n", this._unicname);
sb.AppendFormat(" specialuseonly = {0},\r\n", this._specialuseonly);
if (_BonusGroupList.Count > 0) { foreach (S2EdBlPrBonusGroup obj in _BonusGroupList) { sb.Append(obj.ToString()); } }
if (!S2EdParseCtrl.IsString(this._itemtypes)) sb.AppendFormat(" itemtypes = {{{0}}},\r\n", this._itemtypes);
if (!S2EdParseCtrl.IsString(this._wearergroups)) sb.AppendFormat(" wearergroups = {{\'{0}\',}},\r\n", this._wearergroups);
sb.AppendFormat("}}\r\nmgr.createBlueprint({0}, newBlueprint);\r\n", this._s2ObjectId); return sb.ToString(); }
#irgenwo
streamwriter sw = new ........
sw.Writeline(s2object.ToString() ); |
also schon menge strings die da reingepackt werden
das gegenstück (mein favorit)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37:
| public override void Write(StreamWriter sw) { sw.WriteLine("newBlueprint = {");
if (S2EdParseCtrl.IsString(this._s2ObjectInfo) == true) sw.WriteLine("--# {0}", this._s2ObjectInfo);
sw.WriteLine(" id = {0},", this._s2ObjectId); sw.WriteLine(" name = \"{0}\",", this._s2ObjectName); sw.WriteLine(" palettebits = \"{0}\",", this._palettebits); sw.WriteLine(" dmgvariation = {0},", this._dmgvariation); this.MinConStraints.Write(sw); sw.WriteLine(" lvljump = {0},", this._lvljump); sw.WriteLine(" usability = {0},", this._usability); this.AllotmentPmfpi.Write(sw);
if (!S2EdParseCtrl.IsString(this._unicname)) sw.WriteLine(" uniquename = \"{0}\",", this._unicname);
sw.WriteLine(" specialuseonly = {0},", this._specialuseonly);
if (_BonusGroupList.Count > 0) { foreach (S2EdBlPrBonusGroup obj in _BonusGroupList) { obj.Write(sw); } }
if (!S2EdParseCtrl.IsString(this._itemtypes)) sw.WriteLine(" itemtypes = {{{0},}},", this._itemtypes);
if (!S2EdParseCtrl.IsString(this._wearergroups)) sw.WriteLine(" wearergroups = {{\'{0}\',}},", this._wearergroups);
sw.WriteLine("}}\nmgr.createBlueprint({0}, newBlueprint);\n", this._s2ObjectId); } |
das letztere sagt mir mein bauchgefühl ist vom speichermanagment besser ,da ich die daten direkt in dehn streambuffer schreibe (glaub ich zumindenst)
mfg nuckey, this._s2ObjectName);
sw.WriteLine(
Moderiert von
Christian S.: Code- durch C#-Tags ersetzt
Yogu - Sa 14.04.12 17:30
Hallo,
dein Beispiel mit dem StringBuilder sieht so unübersichtlich aus, dass ich davon abraten würde. Ich könnte mir gut vorstellen, dass ich bei so etwas schnell mal ein \r oder \n vergessen würde.
Am effizientesten wäre es wohl, direkt in den StreamWriter zu schreiben, allerdings AutoFlush auf false zu setzen und am Ende der Methode Flush aufzurufen. Dann landen alle Daten direkt im Writer-Buffer, werden also nicht doppelt gepuffert, was ja zusätzliche Datenverschiebungen mit sich ziehen würden. Das manuelle Flushen sorgt dafür, dass die Paketgröße des Streams ausgenutzt wird und nicht für jede kurze Zeile ein eigenes TCP/IP-Paket losgeschickt wird.
Grüße,
Yogu
Nuckey - Sa 14.04.12 17:44
hi yogu:
danke für dehn tip.
mit tcp/p hat es nix zu tun ;)
wie ist das verhalten von streamwriter wenn das stringpacket grösser ist als der interne buffer ??
soweit ich es weiss ist dieser auf 1024 begrenzt.
wie schon beschrieben möchte ich so wenig an speicher verschwenden ,denn es werden bis zu 50000 objecte angelegt und geschrieben.
bei verwendung der using direktive müsste das schreiben automatisch geschehen oder?
Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| using(StreamWriter sw = new ....) { sw.AutoFlush = false;
sw.Writeline.... . . } hier müste autom. close erfolgen und somit auch das schreiben |
oder
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Autoflush = false;
public void write(StreamWriter sw) { sw.Write . . . flush(); } |
mfg nuckey
Yogu - So 15.04.12 14:42
Nuckey hat folgendes geschrieben : |
| mit tcp/p hat es nix zu tun ;) |
Hups, ich da habe ich von meinem eigenen Projekt auf deines geschlossen ;)
Dann geht's wohl um einen Dateizugriff? In diesem Fall kann es sein, dass das manuelle Flushen gar nichts mehr bringt, da das Betriebssystem Dateizugriffe ohnehin optimiert. Ich kann mir gut vorstellen, dass da erstmal in den Arbeitsspeicher geschrieben wird und nur hin und wieder, vor allem eben beim Schließen der Festplattenzugriff erfolgt. Ist aber nur eine Vermutung.
Nuckey hat folgendes geschrieben : |
wie ist das verhalten von streamwriter wenn das stringpacket grösser ist als der interne buffer ??
soweit ich es weiss ist dieser auf 1024 begrenzt. |
Dann wird
Flush implizit aufgerufen:
Nuckey hat folgendes geschrieben : |
| wie schon beschrieben möchte ich so wenig an speicher verschwenden ,denn es werden bis zu 50000 objecte angelegt und geschrieben. |
Dann würde ich - wie ich es ja bereits getan habe ;) - vom
StringBuilder abraten. Der würde nämlich die Daten durch eine weitere Speicherzelle schliefen.
Nuckey hat folgendes geschrieben : |
bei verwendung der using direktive müsste das schreiben automatisch geschehen oder?
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| using(StreamWriter sw = new ....) { sw.AutoFlush = false;
sw.Writeline.... . . } hier müste autom. close erfolgen und somit auch das schreiben |
oder
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Autoflush = false;
public void write(StreamWriter sw) { sw.Write . . . flush(); } | |
Beide Quelltexte werden korrekt flushen.
Grüße,
Yogu
Ralf Jansen - So 15.04.12 15:56
| Zitat: |
| soweit ich es weiss ist dieser auf 1024 begrenzt. |
Kommt drauf an. Wenn du einen der Konstruktoren mit Path benutzt hast wird der StreamWriter einen eigenen Filestream erzeugen und einen 4K Buffer (übliche Sektorgröße einer Festplatte) benutzen. Wenn du einen selbst erzeugten Stream (auch wenn dieser ein Filestream ist) übergibst wird ein 1K Buffer verwendet. In beiden Fällen gilt das natürlich nur wenn du nicht selbst eine Puffergröße übergeben hast.
Nuckey - Mo 16.04.12 18:38
danke euch .
der stream wird per using anweisung geöffnet/geschlossen.
die writemethode wird jetz so aufgerufen
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| public void Write(StreamWriter sw) { sw.AutoFlush = false; sw.Write ... .... . . sw.Flush() } |
und mit dehm puffer zuweisen ist mir neu darüber steht nix in dehn buch.
zumindenst weiss ich jetz in welche richtung ich weiter suchen muss ;).
danke nochmal
mfg nuckey
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!