[allgemeinen Dateizugriff] Geschwindigkeit beim Schreiben von Dateien
spacer
Autor Nachricht
baka0815
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 452
Erhaltene Danke: 10

Win XP, Debian GNU/Linux
Delphi 2007 Enterprise, Java, C#
BeitragVerfasst: Di 10.01.12 13:07 
Betrifft: allgemeinen Dateizugriff
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:
ausblenden volle Höhe Delphi-Quelltext markieren
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; // 10.000.000
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!
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
Werbung ausblenden? Dann registriere Dich kostenlos. Weitere Gründe für eine Registrierung.


Werbung ausblenden? Dann registriere Dich kostenlos. Weitere Gründe für eine Registrierung.
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Moderator
Beiträge: 2837
Erhaltene Danke: 182

Win 2000, Win XP
Delphi 7, Turbo Delphi Exp.
BeitragVerfasst: 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."
Ich code EdgeMonkey -~==~- #ee-lounge in Freenode
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
baka0815 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 452
Erhaltene Danke: 10

Win XP, Debian GNU/Linux
Delphi 2007 Enterprise, Java, C#
BeitragVerfasst: 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?
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Moderator
Beiträge: 2837
Erhaltene Danke: 182

Win 2000, Win XP
Delphi 7, Turbo Delphi Exp.
BeitragVerfasst: Mi 11.01.12 12:28 
user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
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.

user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
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 :?


user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
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."
Ich code EdgeMonkey -~==~- #ee-lounge in Freenode
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 15840
Erhaltene Danke: 741

XP, W7 x64 (Chrome, IE9, FF), Debian, (OSX 10.7)
RAD XE 2, Java (NB), C++, C# (VS 2010), JS/HTML, PHP, Lazarus
BeitragVerfasst: Mi 11.01.12 12:46 
user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
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:
www.delphi-forum.de/viewtopic.php?t=100088
(Und wenn nicht, sollte zumindest darauf aufzubauen sein. ;-))
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
baka0815 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 452
Erhaltene Danke: 10

Win XP, Debian GNU/Linux
Delphi 2007 Enterprise, Java, C#
BeitragVerfasst: 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
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starhalf offtopic starofftopic star
Beiträge: 8625
Erhaltene Danke: 147

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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.
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
home home