| Autor |
Beitrag |
freedy
      
Beiträge: 403
Erhaltene Danke: 1
Winows 7
Delphi XE
|
Verfasst: Do 04.01.07 12:25
Hallo Forum!
Ich habe folgendes Problem:
Eine untypisierte Datei (>500MB) enthält in beliebiger Reihenfolge Datensätze unterschiedlicher Länge. Über eine Indexdatei können Art und Dateiposition der Datensätze ausgemacht werden. Ich springe mit dem Delphi-Befehl "Seek" an die jeweilige Dateiposition.
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:
| begin {$I-} Reset(BinFile); Reset(IdxFile); {$I+} if (IOResult <> 0) and FileExists(FileName) then begin try AssignFile(BinFile, FileName); AssignFile(Idxfile, ChangeFileExt(FileName, '.idx'));
Reset(BinFile); Reset(IdxFile);
IdxSize := FileSize(IdxFile);
SetLength(FileIdx, IdxSize div 5 - 1);
for I := 0 to (IdxSize div 5) - 1 do begin ReadID(Idxfile, ID, FPos); FileIdx[I].ID := ID; FileIdx[I].FilePos := FPos; end;
for I := 0 to Length(FileIdx) - 1 do begin Seek(BinFile, FileIdx[I].FilePos); Read(Binfile, FileIdx[I].ID); end;
finally CloseFile(BinFile); CloseFile(IdxFile); end; end; end; |
Die Größe der Binärdatei macht es unmöglich, sie komplett in den Speicher zu laden. Wenn ich aber die Seek-Funktion benutze, wird die gesamte Prozedur zum Ende hin immer langsamer. Gibt es da etwas schnelleres?
freedy
|
|
jasocul
      
Beiträge: 6395
Erhaltene Danke: 149
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Do 04.01.07 12:41
freedy hat folgendes geschrieben: | Hallo Forum!
Ich habe folgendes Problem:
Eine untypisierte Datei (>500MB) enthält in beliebiger Reihenfolge Datensätze unterschiedlicher Länge. |  Du solltest Dein Konzept überdenken.
freedy hat folgendes geschrieben: | | Die Größe der Binärdatei macht es unmöglich, sie komplett in den Speicher zu laden. Wenn ich aber die Seek-Funktion benutze, wird die gesamte Prozedur zum Ende hin immer langsamer. Gibt es da etwas schnelleres? |
Irgendwann reicht der Speicher nicht mehr. Also fängt Windows an, die Auslagerungsdatei zu verwenden. Das ist leider langsamer. Also Konzept überdenken (ich wiederhole mich  ). Das einfachste wäre, nicht alles zu laden, sondern nur das, was man benötigt. Ich nehme nicht an, dass alle Daten gleichzeitig sichtbar sein müssen.
|
|
freedy 
      
Beiträge: 403
Erhaltene Danke: 1
Winows 7
Delphi XE
|
Verfasst: Do 04.01.07 12:47
An der Reihenfolge und Größe der Datei kann ich nichts ändern. Es sind Meßwerte, die alle 0,5 Sekunden gespeichert werden. Die Zeit reicht da auch nicht zum Sortieren oder Ähnlichem. Die Testdateien jetzt haben schon eine Größe von 500MB. Wie es nachher wird, wenn die Erfassung über mehrere Tage geht... puh...
Die Daten sollen nicht permanent sichtbar sein. Das ist schon richtig. Ich muss aber einen Verlauf der Meßwerte darstellen können. Dazu muss ich jeden Datensatz zumindest einmal anfassen, auslesen und auswerten. Das dauert schon seine Zeit. Aber der zeitliche Verlauf nimmt gegen Ende hin zu, was ich mir nur durch die Seek-Funktion erklären kann.
Deshalb eigentlich ganz einfach gefragt: gibt es da etwas schnelleres?
|
|
jasocul
      
Beiträge: 6395
Erhaltene Danke: 149
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Do 04.01.07 13:18
Das Seek ist das kleinere Problem. Du liest die Werte ein und verarbeitest diese. Diese Daten hältst du vermutlich irgendwie im Speicher. Ansonsten könntest Du ja keinen Verlauf darstellen. Irgendwann ist der Speicher voll und die Auslagerungsdatei wird genutzt. Geschwindigkeit Hauptspeicher > Geschwindigkeit Festplatte!
Deine Datei ist untypisiert und sehr groß. Die Länge der Datensätze ist unterschiedlich. Mit jedem Seek und Read machst du einen Plattenzugriff. Dazu kommt dann irgendwann die Auslagerungsdatei. Interessant, um das ganz zu optimieren, wäre Deie Read-Routine. Benutzt Du da BlockRead oder Streams? Dein Seek deutet darauf hin, dass du wie auf eine typisierte Datei zugreifst und dann Byte-Weise einliest, bis zur nächsten Datensatzposition, die in deiner Index-Liste steht.
Es ist schwer Dir einen Tipp zu geben, wenn man nicht weiß, wie Du auf die Daten genau zugreifst. Ich kann leider nur Vermutungen anstellen.
|
|
Chryzler
      
Beiträge: 1097
Erhaltene Danke: 2
|
Verfasst: Do 04.01.07 13:28
Ich würde statt einer großen Datei einfach mehrere Kleine nehmen. Wenn du die Daten aufnimmst, speicherst du einfach alle 10 Minuten die Daten als neue Datei ab, und fängst eine neue an. Dann hast du niemals zu viel im Speicher.
|
|
freedy 
      
Beiträge: 403
Erhaltene Danke: 1
Winows 7
Delphi XE
|
Verfasst: Do 04.01.07 13:50
jasocul hat folgendes geschrieben: | Das Seek ist das kleinere Problem. Du liest die Werte ein und verarbeitest diese. Diese Daten hältst du vermutlich irgendwie im Speicher. Ansonsten könntest Du ja keinen Verlauf darstellen. Irgendwann ist der Speicher voll und die Auslagerungsdatei wird genutzt. Geschwindigkeit Hauptspeicher > Geschwindigkeit Festplatte!
Deine Datei ist untypisiert und sehr groß. Die Länge der Datensätze ist unterschiedlich. Mit jedem Seek und Read machst du einen Plattenzugriff. Dazu kommt dann irgendwann die Auslagerungsdatei. Interessant, um das ganz zu optimieren, wäre Deie Read-Routine. Benutzt Du da BlockRead oder Streams? Dein Seek deutet darauf hin, dass du wie auf eine typisierte Datei zugreifst und dann Byte-Weise einliest, bis zur nächsten Datensatzposition, die in deiner Index-Liste steht.
|
Ich benutze "BlockRead". Die Daten werden aber definitiv nur einmalig in den Speicher geholt und dann wieder gelöscht. Zwischengehalten werden Minimal- und Maximalwert des gelesenen Datensatzes. Der Rest wird die Pufferfreigabe wieder gelöscht.
Ich vermute eher, dass Seek folgendes macht und deshalb der Geschwindigkeitsverlust auftritt:
1. Positionieren auf Dateiposition 0
2. Schrittweise weitersetzen auf gewünschte Dateiposition
Das erklärt, warum am Anfang alles relativ flüssig läuft und gegen Ende immer langsamer. Wenn ich mich richtig erinnere, macht "FileSeek" eine ähnliche Operation nur relativ zur gegenwärtigen Zeigerposition, oder?
|
|
IngoD7
      
Beiträge: 629
D7
|
Verfasst: Do 04.01.07 13:55
Wenn jasoculs Vermutung von wegen "Speicher goes to Auslagerungsdatei"  stimmt (und davon gehe ich aus), dann nützt auch eine optimierte Einleseroutine nichts, solange solche Monsterdateien und seek beteiligt sind.
Ist es nicht auch so, dass seek umso länger dauert, je weiter hinten in der Datei positioniert wird?
Wie auch immer: Die Quelldateien sollten kleiner sein. Alles andere wäre höchstwahrscheinlich Murks. Ich kann mir sowieso nur schwer vorstellen, warum Meßwerte, die im 500ms-Rythmus genommen werden, über mehrere Tage abgebildet werden sollen. Muss die Auswertung/Grafik derart fein sein, oder soll das nur eine neue Wandtapete werden?
Soll heißen: Quelldateien verkleinern und nötigenfalls eben mehrere (kleine) davon zur Auswertung heranziehen (anstatt einem Monster). Dann geht zumindest die Positionierung mittels seek schneller.
|
|
freedy 
      
Beiträge: 403
Erhaltene Danke: 1
Winows 7
Delphi XE
|
Verfasst: Do 04.01.07 14:04
IngoD7 hat folgendes geschrieben: | Wenn jasoculs Vermutung von wegen "Speicher goes to Auslagerungsdatei" stimmt (und davon gehe ich aus), |
Definitiv nicht beteiligt. Die gesamte Speicherauslastung (ich habe gerade nochmal alles ausgewertet) des Programms liegt bei 12 MB. Das ist wirklich nicht viel.
Die Geschwindigkeit geht auch in den Keller, wenn ich KEINE Daten lese.
IngoD7 hat folgendes geschrieben: |
Ist es nicht auch so, dass seek umso länger dauert, je weiter hinten in der Datei positioniert wird? |
Sagte ich doch.
IngoD7 hat folgendes geschrieben: |
Wie auch immer: Die Quelldateien sollten kleiner sein. Alles andere wäre höchstwahrscheinlich Murks. Ich kann mir sowieso nur schwer vorstellen, warum Meßwerte, die im 500ms-Rythmus genommen werden, über mehrere Tage abgebildet werden sollen. Muss die Auswertung/Grafik derart fein sein? |
Ja, ich muss einen Minima/Maxima-Verlauf der gesamten Messung darstellen können. Und noch ein paar andere Scherze. Kundenwunsch eben.
IngoD7 hat folgendes geschrieben: | | Quelldateien verkleinern und nötigenfalls eben mehrere (kleine) davon zur Auswertung heranziehen (anstatt einem Monster). Dann geht zumindest die Positionierung mittels seek schneller. |
Leider ist auch das Monster Kundenwunsch. Wir haben das "erstmal" so verkauft. Der Kunde war damit aber keineswegs zufrieden. Verständlich. Wer will schon 30Min auf einen zweiseitigen Bericht warten?
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Do 04.01.07 14:30
freedy hat folgendes geschrieben: | | Die Geschwindigkeit geht auch in den Keller, wenn ich KEINE Daten lese. |
Um sicher zu gehen: Also auch, wenn Zeile 33 auskommentiert ist?
Möglicherweise ist TFileStream effektiver, das ist ja schnell getestet. Ansonsten würde ich es mit MMFs (Memory Mapped Files) probieren, bei denen kannst du dir einzlene Views in den Adressraum mappen, z.B. immer 1MB am Stück, und darauf zugreifen wie auf einen Pointer.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
jasocul
      
Beiträge: 6395
Erhaltene Danke: 149
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Do 04.01.07 14:32
Wäre es machbar, die Daten in eine Datenbank zu importieren? Das dürfte für die Auswertungen (->SQL) auch einfacher werden.
Eine andere Möglichkeit:
Über Deine Index-Datei kannst Du die Daten-Datei doch in anderen Blockgrößen einlesen. Also einfach mal eben 1000 Datensätze einlesen und diese dann im Hauptspeicher verarbeiten. Dadurch sparst gaaaaaanz viele Seeks. Ob Du nun mit BlockRead nur einen Datensatz einliest oder 1000 ist ziemlich egal. Aber Du hast dadurch nur ein teausendstel an Dateizugriffen.
|
|
IngoD7
      
Beiträge: 629
D7
|
Verfasst: Do 04.01.07 14:34
|
|
freedy 
      
Beiträge: 403
Erhaltene Danke: 1
Winows 7
Delphi XE
|
Verfasst: Do 04.01.07 14:59
tommie-lie hat folgendes geschrieben: | | Um sicher zu gehen: Also auch, wenn Zeile 33 auskommentiert ist? |
Ja, genau
tommie-lie hat folgendes geschrieben: | | Möglicherweise ist TFileStream effektiver, das ist ja schnell getestet. Ansonsten würde ich es mit MMFs (Memory Mapped Files) probieren, bei denen kannst du dir einzlene Views in den Adressraum mappen, z.B. immer 1MB am Stück, und darauf zugreifen wie auf einen Pointer. |
Werde ich mal ausprobieren. Mit MMFs habe ich noch nicht gearbeitet. Gibt es da schon fertige Klassen?
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Do 04.01.07 15:09
freedy hat folgendes geschrieben: | | Mit MMFs habe ich noch nicht gearbeitet. Gibt es da schon fertige Klassen? |
Keine Ahnung, aber das sind 5 Funktionen, die du im SDK findest (über CreateFileMapping findest du die restlichen), von denen du 3 brauchst.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
Reinhard Kern
      
Beiträge: 591
Erhaltene Danke: 14
|
Verfasst: Fr 05.01.07 01:41
freedy hat folgendes geschrieben: | An der Reihenfolge und Größe der Datei kann ich nichts ändern. Es sind Meßwerte, die alle 0,5 Sekunden gespeichert werden. Die Zeit reicht da auch nicht zum Sortieren oder Ähnlichem. Die Testdateien jetzt haben schon eine Größe von 500MB. Wie es nachher wird, wenn die Erfassung über mehrere Tage geht... puh...
Die Daten sollen nicht permanent sichtbar sein. Das ist schon richtig. Ich muss aber einen Verlauf der Meßwerte darstellen können. Dazu muss ich jeden Datensatz zumindest einmal anfassen, auslesen und auswerten. Das dauert schon seine Zeit. Aber der zeitliche Verlauf nimmt gegen Ende hin zu, was ich mir nur durch die Seek-Funktion erklären kann.
Deshalb eigentlich ganz einfach gefragt: gibt es da etwas schnelleres? |
Hallo,
ich habe eine solche Software zur Verlaufsdarstellung erstellt, die liest aber nicht mehr ein als notwendig: man muss sich bloss Gedanken machen, wieviel Punkte man eigentlich braucht, auf einem Bildschirm mit 1024 Pixeln etwa ist es sinnlos, mehr als 1024 Messpunkte im Speicher zu halten. Wenn ich also 100000 Messungen habe, bilde ich gleich beim Einlesen den Mittelwert aus jeweils 100 aufeinanderfolgenden Messwerten.
Eine Software, die für eine völlig beliebige Anzahl von Messwerten eine sinnvolle Verlaufszeichnung erstellt, ist auch nicht ganz unkomplex (meine skaliert aufwärts und abwärts, kann also sowohl 10 als auch 1 Mio Messwerte darstellen), aber in keinem Fall brauche ich wirklich hunderte von MB im Speicher für einen Verlauf. Selbst wenn ich jedes Pixel eines A3-Lasers ausnutzen würde, brauche ich nicht mehr als 20000 Punkte, aber das ist schon unnötig genau.
Gruss Reinhard
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 05.01.07 03:01
@ freedy:
Du hast gar nichts zu Datenbanken gesagt, die jasocul vorgeschlagen hat.
Mit einer Datenbank wärst du auf jeden Fall schneller als mit untypisierten Dateien oder TFileStream oder so. Und das sowohl beim Eintragen als auch beim Auslesen. Zudem könntest du (wie auch bereits angedeutet) auch komplexe Filterungsoperationen durch bloße SQL-Statements lösen.
Und so kompliziert sind Datenbanken ja nun auch nicht. (Ok, bevor ich das erste Mal wirklich damit gearbeitet habe, habe ich das mal gedacht...) Aber solange du nicht gerade die  BDE nimmst, solltest du damit keine Probleme bekommen.
|
|
freedy 
      
Beiträge: 403
Erhaltene Danke: 1
Winows 7
Delphi XE
|
Verfasst: Fr 05.01.07 10:42
Reinhard Kern hat folgendes geschrieben: | freedy hat folgendes geschrieben: | An der Reihenfolge und Größe der Datei kann ich nichts ändern. Es sind Meßwerte, die alle 0,5 Sekunden gespeichert werden. Die Zeit reicht da auch nicht zum Sortieren oder Ähnlichem. Die Testdateien jetzt haben schon eine Größe von 500MB. Wie es nachher wird, wenn die Erfassung über mehrere Tage geht... puh...
Die Daten sollen nicht permanent sichtbar sein. Das ist schon richtig. Ich muss aber einen Verlauf der Meßwerte darstellen können. Dazu muss ich jeden Datensatz zumindest einmal anfassen, auslesen und auswerten. Das dauert schon seine Zeit. Aber der zeitliche Verlauf nimmt gegen Ende hin zu, was ich mir nur durch die Seek-Funktion erklären kann.
Deshalb eigentlich ganz einfach gefragt: gibt es da etwas schnelleres? |
Hallo,
ich habe eine solche Software zur Verlaufsdarstellung erstellt, die liest aber nicht mehr ein als notwendig: man muss sich bloss Gedanken machen, wieviel Punkte man eigentlich braucht, auf einem Bildschirm mit 1024 Pixeln etwa ist es sinnlos, mehr als 1024 Messpunkte im Speicher zu halten. Wenn ich also 100000 Messungen habe, bilde ich gleich beim Einlesen den Mittelwert aus jeweils 100 aufeinanderfolgenden Messwerten.
Eine Software, die für eine völlig beliebige Anzahl von Messwerten eine sinnvolle Verlaufszeichnung erstellt, ist auch nicht ganz unkomplex (meine skaliert aufwärts und abwärts, kann also sowohl 10 als auch 1 Mio Messwerte darstellen), aber in keinem Fall brauche ich wirklich hunderte von MB im Speicher für einen Verlauf. Selbst wenn ich jedes Pixel eines A3-Lasers ausnutzen würde, brauche ich nicht mehr als 20000 Punkte, aber das ist schon unnötig genau.
Gruss Reinhard |
Hallo Reinhard!
Ich gebe dir 100%ig Recht. Und es ist komplex, vom Benutzer frei einstellbar ist, welcher Messwertzyklus abspeichern werden soll. Wir haben allerdings Kunden, die jeden Zyklus abspeichern. Deshalb muss auch jeder Zyklus in die Berechnungen mit eingehen. Das heißt, der Verlauf ist nicht alles. Wenn es "nur" der Min-Max-Verlauf wäre, würde ich die Werte gleich in ein eigenes Datenfeld wegschreiben. Das ist also weniger das Problem. Es gibt da nur noch ein paar fieser Sachen, die ich während des Versuchs nicht laufen lassen möchte (FFTs, Ausgleichsrechnungen etc.).
Eine Datenbank finde ich eher unpassend, da die Installation bei unseren Firmenkunden erhebliche Probleme macht. Mehr weiß ich darüber auch nicht. Auch ich darf bei der Software keine Installer oder ähnliches benutzen. Nicht mal Registry-Einträge. Naja.
Ich werde erstmal ausprobieren und bedanke mich für die zahlreichen Hinweise.
Michael
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 05.01.07 10:50
Datenbanken gehen auch ohne Installation... Lediglich die BDE müsste installiert werden, aber die würde ich sowieso niemals empfehlen.
Und andere Datenbanken brauchen keinerlei Installation. Die Frage ist lediglich: Welche DB-Komponenten sind besonders schnell bei großén Datenmengen? Es gibt einige DB-Zugriffspakete, die lediglich aus ein paar Units bestehen, aber da weiß ich nicht, welche gut sind.
Insofern würde ich empfehlen, dir mal die DB-Komponenten bei Torry anzusehen.
Was SQL angeht: MySQL ist ja für kommerzielle Nutzung nicht kostenlos. Insofern weiß ich nicht, ob es da andere Lösungen gibt. Aber SQL ist zwar schön, aber unbedingt brauchen tut man es für den DB-Zugriff auch nicht.
|
|
freedy 
      
Beiträge: 403
Erhaltene Danke: 1
Winows 7
Delphi XE
|
Verfasst: Fr 05.01.07 10:56
Naja, mein Favorit wäre die AbsolutDatabase. Nur wenn einem ein Chef mit einem Investitionsplan im Nacken sitzt... Es ist hier alles nicht so einfach  SQL-Abfragen wären aber schon schön.
Ich bin gerade dabei diesen Thread durchzuarbeiten: [allgemeinen Dateizugriff] Einen Record außerhalb der Komponente deklarieren. Geht das?
Vielleichts hilft's.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Fr 05.01.07 11:43
Hallo,
wenn Du die Indexdatei in FileIdx (maximal 12 Mbyte oder?)einlesen kannst( wieso nicht in einem Rutsch, oder sind dort mehr Daten gespeichert?)
kannst Du diese auch innerhalb von 0,5 s nach Fpos (müßte eigentlich Int64 sein, wenn Du schon jetzt bei 500 Mbyte bist) sortieren.
Gruß Horst
|
|
freedy 
      
Beiträge: 403
Erhaltene Danke: 1
Winows 7
Delphi XE
|
Verfasst: Fr 05.01.07 12:41
Die FileIdx zu sortieren ist kein Problem. Abgesehen davon liegt sie mir auch schon sortiert vor. Das hilft mir aber nicht, das "Seek" zu umgehen, was ja noch mein Hauptproblem zu sein scheint. Alternativ könnte ich probieren, den Pointer in der Datei irgendwie zu setzen. Wenn mir das gelänge, wäre es vielleicht noch einfacher, als mit MMFs zu arbeiten.
|
|
|