Autor |
Beitrag |
baka0815
      
Beiträge: 489
Erhaltene Danke: 14
Win 10, Win 8, Debian GNU/Linux
Delphi 10.1 Berlin, Java, C#
|
Verfasst: Di 10.01.12 13:07
Hallo zusammen!
Ich habe mir ein kleines Tool geschrieben um die Geschwindigkeit von WriteLn bei einem TextFile mit TFileStream zu vergleichen.
Herausgekommen sind bei mir große Unterschiede, daher vermute ich den Fehler in meiner Implementierung:
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: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132:
| program Test;
{$APPTYPE CONSOLE}
uses SysUtils, Windows, Classes, Math; const cCount = 10000000; cTestAnz = 20;
var Test: Integer; MinZeit, MaxZeit, ZeitSum, Zeit, Freq: Int64; I: Integer; Anz: Integer; function WriteLnTest: Int64; var Start, Ende: Int64; F: TextFile; I: Integer; Text: string; begin QueryPerformanceCounter(Start); AssignFile(F, 'C:\Test.dat'); try Rewrite(F);
for I := 1 to cCount do begin Text := Format('Wert: %d', [I]); WriteLn(F, Text); if (I mod 100000) = 0 then Write(#13 + Format('Test %2d: ', [Test]) + FormatFloat('000%', (I / cCount) * 100)); end; finally CloseFile(F); end; QueryPerformanceCounter(Ende);
Result := (Ende - Start); end;
function StreamWriteTest: Int64; var Start, Ende: Int64; I: Integer; Stream: TFileStream; Text: string; begin QueryPerformanceCounter(Start);
Stream := TFileStream.Create('C:\TestSt.dat', fmCreate or fmShareExclusive); try for I := 1 to cCount do begin Text := Format('Wert: %d', [I]) + #13#10; Stream.WriteBuffer(Text[1], Length(Text)); if (I mod 100000) = 0 then Write(#13 + Format('Test %2d: ', [Test]) + FormatFloat('000%', (I / cCount) * 100)); end; finally Stream.Free; end; QueryPerformanceCounter(Ende);
Result := (Ende - Start); end;
begin try ZeitSum := 0; MinZeit := MaxLongint; MaxZeit := 0; Anz := 0;
QueryPerformanceFrequency(Freq);
WriteLn('WriteLn-Test'); for I := 1 to cTestAnz do begin Test := I; Zeit := WriteLnTest; ZeitSum := ZeitSum + Zeit; MinZeit := Min(MinZeit, Zeit); MaxZeit := Max(MaxZeit, Zeit);
WriteLn(#13 + Format('Test %2d: 100%%; Zeit: %g', [Test, Zeit/Freq])); Inc(Anz); end; WriteLn('----------------------------------------------'); WriteLn(Format('| Min : %g', [MinZeit/Freq])); WriteLn(Format('| Max : %g', [MaxZeit/Freq])); WriteLn(Format('| Avg : %g', [(ZeitSum/Anz)/Freq])); WriteLn('----------------------------------------------'); WriteLn;
ZeitSum := 0; MinZeit := MaxLongint; MaxZeit := 0; Anz := 0;
QueryPerformanceFrequency(Freq);
WriteLn('StreamWrite-Test'); for I := 1 to cTestAnz do begin Test := I; Zeit := StreamWriteTest; ZeitSum := ZeitSum + Zeit; MinZeit := Min(MinZeit, Zeit); MaxZeit := Max(MaxZeit, Zeit);
WriteLn(#13 + Format('Test %2d: 100%%; Zeit: %g', [Test, Zeit/Freq])); Inc(Anz); end; WriteLn('----------------------------------------------'); WriteLn(Format('| Min : %g', [MinZeit/Freq])); WriteLn(Format('| Max : %g', [MaxZeit/Freq])); WriteLn(Format('| Avg : %g', [(ZeitSum/Anz)/Freq])); WriteLn('----------------------------------------------'); WriteLn; WriteLn('Fertig'); except on E:Exception do Writeln(E.Classname, ': ', E.Message); end; ReadLn; end; |
Hier das Ergebnis:
Die Unterschiede fallen ziemlich groß aus (15 zu 60 Sekunden), daher vermute ich einen Fehler in meiner Implementierung - oder sind die Unterschiede wirklich so groß?
Edit:
Ich habe meinen Test jetzt umgebaut, so dass ich erst in einen TMemoryStream schreibe und diesen dann per CopyFrom in einen TFileStream speichere. Das dauert dann sogar nur noch um die 10 Sekunden (3 Sekunden das Füllen des TMemoryStream, 7 Sekunden das CopyFrom).
Aber die Ursprungsfrage bleibt:
Warum ist das WriteBuffer des TFileStream soviel langsamer als WriteLn?
Einloggen, um Attachments anzusehen!
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Di 10.01.12 20:02
Kurz, hab keine Zeit:
Buffering. Dein Stream buffert gar nicht, TextFile hat 128byte und mit MemoryStream vorher... naja, den ganzen Stream eben.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
baka0815 
      
Beiträge: 489
Erhaltene Danke: 14
Win 10, Win 8, Debian GNU/Linux
Delphi 10.1 Berlin, Java, C#
|
Verfasst: Mi 11.01.12 11:05
Also stimmt meine Vermutung, dass das Write des TFileStream direkt auf die Festplatte schreibt (Flush) und nicht selbst puffert - wieso?
Gibt es in Delphi (wie z.B. in Java) einen BufferedStream, der mir die Pufferung bereits abnimmt oder muss ich mir da komplett selbst was bauen (ich nutze aktuell Delphi 2007).
Wo ist dann der Unterschied zwischen den Funktionen Write und WriteBuffer des TFileStream?
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mi 11.01.12 12:28
baka0815 hat folgendes geschrieben : | Also stimmt meine Vermutung, dass das Write des TFileStream direkt auf die Festplatte schreibt (Flush) und nicht selbst puffert - wieso? |
Geflusht wird nicht direkt, aber auch wenn Windows das selbst nochmal in seinen 64k-Schnipseln buffert ist das vergleichsweise langsam. Vermutlich wegen dem Verwaltungsaufwand - ein WriteFile kostet so um die 5us, besonders wenn man wenig schreibt. Wird nach oben hin natürlich mehr, aber die "Fixkosten" bleiben. Sieht man auch im ProcessMonitor schön.
baka0815 hat folgendes geschrieben : | Gibt es in Delphi (wie z.B. in Java) einen BufferedStream, der mir die Pufferung bereits abnimmt oder muss ich mir da komplett selbst was bauen (ich nutze aktuell Delphi 2007). |
Bis BDS2006 gabs noch keinen. Sowas wollte ich immer mal bauen (und hab auch grade für MUO einen BufferedReadStream geschrieben), aber was komplett immer funktionierendes ist nicht so ganz einfach wie ich feststellen musste
TReader und TWriter Buffern allerdings, vielleicht ist das ja verwendbar.
Das komplette Streamingsystem gehört neugeschrieben, aber das systemweit umzupatchen (immerhin wird TFileStream überall verwendet) ist nicht so ganz einfach. Müsste man mal AndyH fragen. Und, was viel wichtiger ist: müsste man mal Zeit haben
baka0815 hat folgendes geschrieben : | Wo ist dann der Unterschied zwischen den Funktionen Write und WriteBuffer des TFileStream? |
Kein Nennenswerter, nur die Datentypen sind etwas anders.
EDIT: nicht mal das, der Unterschied nur dass *Buffer eine Fehlerprüfung macht und ggf. eine Exception auslöst.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 11.01.12 12:46
baka0815 hat folgendes geschrieben : | Gibt es in Delphi (wie z.B. in Java) einen BufferedStream, der mir die Pufferung bereits abnimmt oder muss ich mir da komplett selbst was bauen (ich nutze aktuell Delphi 2007). |
Ich habe die Art und Weise des Schreibens zwar nicht mehr im Kopf, aber vielleicht ist das ja etwas für dich:
[url] www.delphi-forum.de/...c.php?t=100088[/url]
(Und wenn nicht, sollte zumindest darauf aufzubauen sein.  )
|
|
baka0815 
      
Beiträge: 489
Erhaltene Danke: 14
Win 10, Win 8, Debian GNU/Linux
Delphi 10.1 Berlin, Java, C#
|
Verfasst: Do 12.01.12 16:37
Danke dir für den Tipp, allerdings wäre es schön einen generischen TBufferedStream o.ä. zu haben, den man einfach über einen bestehenden TStream überstülpen kann, damit das nicht nur für Dateizugriff funktioniert.
Für diesen Beitrag haben gedankt: BenBE, Martok
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 16.01.12 22:17
Also wenn es wirklich schnell sein sollte, nimmt man eh MMFs. Dann ist das Limit mehr oder weniger die Geschwindigkeit der Festplatte.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
|