Container zum schnellen Lesen / Schreiben

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
mweihrauch
Beiträge: 2
Registriert: Sa Mai 17, 2014 9:05 pm

Container zum schnellen Lesen / Schreiben

Beitrag von mweihrauch » Sa Mai 17, 2014 9:20 pm

Ich habe folgende Problemstellung:

Ich benötige ein Containerformat (existierend oder selbstgebaut), um z. B. 100.000 "kleine" (10 - 30 KB) jpeg-Bilder in diesem Container (z. B. zip) zu speichern und sehr schnell zu lesen (das Ganze läuft dann auf einem Server und schickt diese kleinen Bilder an die Clients). Je schneller das Lesen aus dem Container funktioniert, desto besser das User-Erlebnis.

Meine Fragen:
Das ZIP Format (ohne Kompression) scheint eigentlich ganz geeignet, da es die Dateien seriell in den ZIP-Container schreibt und am Ende der ZIP-Datei ein Verzeichnis der Dateien erstellt. In diesem Verzeichnis stehen auch die "Offsets" und Längen der einzelnen im Archiv gespeicherten Dateien. Das heißt, man muss nicht das ganze Archiv von vorne nach hinten durchlesen, um nur eine einzelne Datei zu extrahieren. Das ist wichtig, um sehr schnell die Dateien einzeln lesen zu können.

Meine Fragen:

1. Das Verzeichnis aller im ZIP gespeicherten Dateien liegt am Ende der ZIP-Datei. Daher wird dieses Verzeichnis "rückwärts" aus dem ZIP-Archiv als erstes gelesen. Festplatten unterstützen ja aber nativ kein "Rückwärtslesen". Würde es womöglich einen Geschwindigkeitsvorteil bringen, das Verzeichnis der ZIP Datei daher in einer eigenen externen Datei auf der Festplatte abzulegen, um noch schneller lesen zu können?

2. Gibt es bei Dateioperationen einen Geschwindigkeitsunterschied zwischen C oder C++?

3. Wenn ich ein eigenes Containerformat bauen sollte und meine eigenen Read/Write Funktionen schreibe, ist es dann hinsichtlich der Geschwindigkeit egal, ob ich byte-weise lese oder immer größere Teile (mit anderen Worten, wird durch C/C++ oder das System ohnehin performant gepuffert oder muss ich darauf achten)?

Vielen Dank im Voraus!

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Container zum schnellen Lesen / Schreiben

Beitrag von mfro » Sa Mai 17, 2014 11:52 pm

mweihrauch hat geschrieben: ...
Meine Fragen:

1. Das Verzeichnis aller im ZIP gespeicherten Dateien liegt am Ende der ZIP-Datei. Daher wird dieses Verzeichnis "rückwärts" aus dem ZIP-Archiv als erstes gelesen. Festplatten unterstützen ja aber nativ kein "Rückwärtslesen". Würde es womöglich einen Geschwindigkeitsvorteil bringen, das Verzeichnis der ZIP Datei daher in einer eigenen externen Datei auf der Festplatte abzulegen, um noch schneller lesen zu können?
Der Festplatte ist es wurscht, ob sie ihre Schreib-/Leseköpfe nach außen oder nach innen bewegt. Im Übrigen ist gar nicht gesagt, daß "das hintere Ende" einer Datei "hinter dem Anfang" oder vielleicht davor oder gar irgendwo dazwischen liegt, das ist völlig dem Betriebssystem überlassen.
Wenn Du in deinem Programm einen fseek()-Aufruf machst, bewegen sich die Köpfe noch nicht. Es wird nur der Offset irgendwo gemerkt. Also ist auch von daher gleichgültig, ob Du "von hinten" oder "von vorne" anfängst zu lesen.
mweihrauch hat geschrieben: 2. Gibt es bei Dateioperationen einen Geschwindigkeitsunterschied zwischen C oder C++?
Höchstens unwesentliche.
mweihrauch hat geschrieben: 3. Wenn ich ein eigenes Containerformat bauen sollte und meine eigenen Read/Write Funktionen schreibe, ist es dann hinsichtlich der Geschwindigkeit egal, ob ich byte-weise lese oder immer größere Teile (mit anderen Worten, wird durch C/C++ oder das System ohnehin performant gepuffert oder muss ich darauf achten)?
Das hängt davon ab, welche Routinen Du zum Lesen/Schreiben verwendest. Für C stdio-Routinen kannst Du die Puffergröße einstellen (setvbuf()). Mit großen Puffern läßt sich der Overhead für Funktionsaufrufe ein wenig reduzieren, das fällt allerdings angesichts der Schnelligkeit heutiger Rechner im Verhältnis zu Platten so gut wie gar nicht mehr ins Gewicht.

Viel sinnvoller erscheint mir, sich (je nach Betriebs- bzw. Filesystem) Gedanken über die Fragmentierung zu machen oder (z.B.) in eine SSD zu investieren.
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Container zum schnellen Lesen / Schreiben

Beitrag von Xin » So Mai 18, 2014 12:59 am

Moin Moin,
mweihrauch hat geschrieben:Ich benötige ein Containerformat (existierend oder selbstgebaut), um z. B. 100.000 "kleine" (10 - 30 KB) jpeg-Bilder in diesem Container (z. B. zip) zu speichern und sehr schnell zu lesen (das Ganze läuft dann auf einem Server und schickt diese kleinen Bilder an die Clients). Je schneller das Lesen aus dem Container funktioniert, desto besser das User-Erlebnis.
Wie oft soll dieser Container denn geöffnet werden? Wenn der Container immer wieder geöffnet wird, würde ich die Sache indizieren, das geht mit ZIP wohl weniger - der sucht erstmal die 100000 Namen durch, bis er den gesuchten findet.
Wird der Container nur einmalig geöffnet und man springt nur im Container, um die passenden Dateien auszulesen, erscheint mir ZIP unpassend. Daten seriell hintereinander zu packen ist jedenfalls keine große Heldentat, da hat ZIP einen anderen Anspruch - nämlich Dateien kleinzuklopfen. TAR (TapeARchiv) könnte hier eventuell interessanter sein.
mweihrauch hat geschrieben:Das ZIP Format (ohne Kompression) scheint eigentlich ganz geeignet, da es die Dateien seriell in den ZIP-Container schreibt und am Ende der ZIP-Datei ein Verzeichnis der Dateien erstellt. In diesem Verzeichnis stehen auch die "Offsets" und Längen der einzelnen im Archiv gespeicherten Dateien. Das heißt, man muss nicht das ganze Archiv von vorne nach hinten durchlesen, um nur eine einzelne Datei zu extrahieren. Das ist wichtig, um sehr schnell die Dateien einzeln lesen zu können.
Dafür liefert der Computer seit Dekaden ein passendes Containerformat mit: das Verzeichnis.

Da das Verzeichnis offenbar eine zu einfache Lösung zu sein scheint, stellt sich die Frage, weshalb das Verzeichnis ausscheidet, aber ein unkomprimierter, umverschlüsselter ZIP-Container eine Lösung darstellt?
mweihrauch hat geschrieben:1. Das Verzeichnis aller im ZIP gespeicherten Dateien liegt am Ende der ZIP-Datei. Daher wird dieses Verzeichnis "rückwärts" aus dem ZIP-Archiv als erstes gelesen. Festplatten unterstützen ja aber nativ kein "Rückwärtslesen". Würde es womöglich einen Geschwindigkeitsvorteil bringen, das Verzeichnis der ZIP Datei daher in einer eigenen externen Datei auf der Festplatte abzulegen, um noch schneller lesen zu können?
Es würde einen Vorteil bringen, wenn die Klasse das Verzeichnis einmalig liest und dann den Container nicht mehr fragen muss: Das spart Dateioperationen und die sind teuer.
mweihrauch hat geschrieben:2. Gibt es bei Dateioperationen einen Geschwindigkeitsunterschied zwischen C oder C++?
Kurz: Irrelevant.
Lang: Implementationsabhängig - C++-Dateioperationen nutzen implementationsabhängig C-Dateioperationen. Statt direkt zu fragen, fragt man jemand anderen, die C-Operation zu fragen. Das kostet eben mehr Zeit. Im Verhältnis zur eigentlich Dateioperation ist das allerdings irrelevant.
mweihrauch hat geschrieben:3. Wenn ich ein eigenes Containerformat bauen sollte und meine eigenen Read/Write Funktionen schreibe, ist es dann hinsichtlich der Geschwindigkeit egal, ob ich byte-weise lese oder immer größere Teile (mit anderen Worten, wird durch C/C++ oder das System ohnehin performant gepudert oder muss ich darauf achten)?
Je größer die eingelesenen Blöcke, desto effizienter ist das Lesen.

Liegen die Daten auf dem Rechner des Users oder auf einem Server? Im zweiten Fall kann man die Sache sehr beschleunigen, in dem man die Dateioperationen eben weglässt: Nehmen wir die Maximalzahlen: 100000 Bilder mit je 30kb sind 3 GB Informationen. Packen wir noch ein Betriebsystem dazu und einen Service, der die Bilder verteilt, also nehmen wir einen Server mit 4GB RAM, der Service lädt alle Bilder in RAM und nach dem Start des Services gibt es überhaupt keine Dateioperationen mehr, die Kiste kopiert nur noch die angefragte Datei aus dem RAM ins Netz.

Ich gehe bisher davon aus, dass der Container nicht modifiziert werden muss, also keine Daten eingefügt oder gelöscht werden. In dem Fall würde ich ein einen indizierten Container schreiben, der z.B. über binäre Suche bei einem Namen oder eben per direktem Zugriff (numerische Id) sich das Offset raussucht, dahinspringt und die Daten zur Weiterverarbeitung in den Speicher packt.

Nehmen wir eine numerische Id. Ganz vorne packt man reine, wieviele Bilder es gibt: 100000.
Wenn ich den Container öffne habe ich also direkt die Information, dass 100000 Bilder da sind. Eine Id 100001 kann ich also sofort verwerfen. Eine Id 4711 würde ich finden. Jede Id ist 4 oder 8 Byte groß, ich überspringe also 4710*4 bzw. 8 Bytes, die ich gar nicht erst einlese. Hier finde ich nun das Offset, wo die Daten für die Id 4711 im Container sind. Ich lade also den Offset-Wert ein und springe dahin. Hier finde ich die erst Größe, lade also 4 Bytes ein, um die Größe herauszufinden und dann folgt ein Befehl, der von dieser Stelle im Container das komplette Bild in den Speicher schaufelt. Container schließen, fertig.
Kann man den Container die ganze Zeit offen halten, würde ich die Index-Tabelle und die einzelnen Größen in den Speicher laden (dann hol auch die Größen gleich mit in die Index-Tabelle packen).
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

mweihrauch
Beiträge: 2
Registriert: Sa Mai 17, 2014 9:05 pm

Re: Container zum schnellen Lesen / Schreiben

Beitrag von mweihrauch » So Mai 18, 2014 2:58 pm

Vielen Dank für die guten Ideen!

Der Sinn ist der folgende:

Ich möchte diese ca. 100.000 Dateien, die in den Verzeichnissen von "0" bis "18" untergebracht sind, in Container schreiben, weil das Hin- und Hertransportieren dieser Dateien zwischen Servern fast unmöglich ist (außer man hat seine Server im gleichen Netzwerk und nutzt DFS, was wir leider nicht machen können). Wenn sie gepackt sind, lassen sich die Container leichter benennen und per FTP, etc transportieren. V. a. Dateioperationen sind bei Windows mit vielen Dateien sehr langsam.

Wir haben außderm die Situation, dass wir nicht nur 1 Container insgesamt haben, sondern ca. 1000 Container, gesamt ca. 1 TB mit insgesamt ca. 100 Mio kleinen Jpegs (ca. 100.000 pro Container). Daher können wir nicht alle Verzeichnisse (also Dateiname + Offset + Größe) der Containerdateien einmal im RAM "vorcachen".

Ev. würde ich also einen Hashtable als Verzeichnis schreiben, in dem das Ganze schön vorsortiert ist.

Nochmal: Danke für die guten Ideen!

Antworten