Gibt es einen Vorteil für die Analysegeschwindigkeit oder die Speichernutzung bei der Verwendung von HDF5 für große Array-Speicher (anstelle von flachen Binärdateien)?


95

Ich verarbeite große 3D-Arrays, die ich oft auf verschiedene Arten in Scheiben schneiden muss, um eine Vielzahl von Datenanalysen durchzuführen. Ein typischer "Würfel" kann ~ 100 GB groß sein (und wird wahrscheinlich in Zukunft größer werden)

Es scheint, dass das typische empfohlene Dateiformat für große Datenmengen in Python die Verwendung von HDF5 (entweder h5py oder pytables) ist. Meine Frage ist: Gibt es einen Vorteil für die Geschwindigkeit oder die Speichernutzung bei der Verwendung von HDF5 zum Speichern und Analysieren dieser Cubes gegenüber dem Speichern in einfachen flachen Binärdateien? Ist HDF5 besser für tabellarische Daten geeignet als für große Arrays, mit denen ich arbeite? Ich sehe, dass HDF5 eine gute Komprimierung bieten kann, aber ich bin mehr an der Verarbeitungsgeschwindigkeit und dem Umgang mit Speicherüberlauf interessiert.

Ich möchte häufig nur eine große Teilmenge des Würfels analysieren. Ein Nachteil von pytables und h5py ist, dass ich, wenn ich ein Stück des Arrays nehme, immer ein numpy-Array zurück bekomme, das Speicher verbraucht. Wenn ich jedoch eine numpy-Memmap einer flachen Binärdatei schneide, kann ich eine Ansicht erhalten, in der die Daten auf der Festplatte gespeichert bleiben. Es scheint also, dass ich bestimmte Sektoren meiner Daten einfacher analysieren kann, ohne meinen Speicher zu überlasten.

Ich habe sowohl pytables als auch h5py untersucht und den Nutzen von beidem bisher für meinen Zweck nicht gesehen.


1
HDF ist ein "Chunked" -Dateiformat. Im Durchschnitt erhalten Sie viel schnellere Lesevorgänge für einen beliebigen Teil Ihres Datensatzes. Eine Memmap hat einen schnellen Best-Case, aber einen sehr, sehr langsamen Worst-Case. h5pyist besser für Datensätze wie Ihren geeignet als pytables. Auch h5pyist nicht einen im Speicher numpy Array zurück. Stattdessen wird etwas zurückgegeben, das sich wie eines verhält, aber nicht in den Speicher geladen wird (ähnlich einem memmappedArray). Ich schreibe eine vollständigere Antwort (kann sie möglicherweise nicht beenden), aber hoffentlich hilft dieser Kommentar in der Zwischenzeit ein wenig.
Joe Kington

Vielen Dank. Ich bin damit einverstanden, dass h5py einen Datensatz zurückgibt, der einer Memmap ähnelt. Wenn Sie jedoch einen Teil des h5py-Datasets erstellen, wird ein numpy-Array zurückgegeben, was meiner Meinung nach (?) Bedeutet, dass die Daten unnötig gespeichert wurden. Ein Memmamp gibt nach Möglichkeit eine Ansicht zur ursprünglichen Memmap zurück. Mit anderen Worten: type(cube)gibt h5py._hl.dataset.Dataset. Während type(cube[0:1,:,:])gibt numpy.ndarray.
Caleb

Ihr Punkt über die durchschnittliche Lesezeit ist jedoch interessant.
Caleb

4
Wenn Sie einen E / A-Engpass haben, kann die Komprimierung in vielen Fällen die Lese- / Schreibleistung verbessern (insbesondere bei Verwendung schneller Komprimierungsbibliotheken wie BLOSC und LZO), da sie die erforderliche E / A-Bandbreite auf Kosten einiger zusätzlicher CPU-Zyklen verringert . Vielleicht möchten Sie sich diese Seite ansehen , die viele Informationen zur Optimierung der Lese- / Schreibleistung mithilfe von PyTables HDF5-Dateien enthält.
Ali_m

2
"Wenn ich eine numpy-Memmap einer flachen Binärdatei schneide, kann ich eine Ansicht erhalten, die die Daten auf der Festplatte speichert" - das mag wahr sein, aber wenn Sie tatsächlich etwas mit den Werten in diesem Array tun möchten, dann früher oder später Sie müssen sie in den Arbeitsspeicher laden. Ein Array mit Speicherzuordnung bietet nur eine Kapselung, sodass Sie nicht genau darüber nachdenken müssen, wann die Daten gelesen werden oder ob sie Ihre Systemspeicherkapazität überschreiten. Unter bestimmten Umständen kann das native Caching-Verhalten von Memmap-Arrays tatsächlich sehr suboptimal sein .
Ali_m

Antworten:


157

HDF5-Vorteile: Organisation, Flexibilität, Interoperabilität

Einige der Hauptvorteile von HDF5 sind seine hierarchische Struktur (ähnlich wie bei Ordnern / Dateien), optionale beliebige Metadaten, die mit jedem Element gespeichert werden, und seine Flexibilität (z. B. Komprimierung). Diese Organisationsstruktur und die Speicherung von Metadaten mögen trivial klingen, sind aber in der Praxis sehr nützlich.

Ein weiterer Vorteil von HDF besteht darin, dass die Datensätze entweder eine feste Größe oder eine feste Größe haben können flexible Größe haben können. Daher ist es einfach, Daten an ein großes Dataset anzuhängen, ohne eine vollständige neue Kopie erstellen zu müssen.

Darüber hinaus ist HDF5 ein standardisiertes Format mit Bibliotheken, die für nahezu jede Sprache verfügbar sind. Daher ist es mit HDF sehr einfach, Ihre Daten auf der Festplatte zwischen Matlab, Fortran, R, C und Python auszutauschen. (Um fair zu sein, ist es auch mit einem großen binären Array nicht allzu schwierig, solange Sie die Reihenfolge C gegen F kennen und die Form, den Typ usw. des gespeicherten Arrays kennen.)

HDF-Vorteile für ein großes Array: Schnellere E / A eines beliebigen Slice

Genau wie beim TL / DR: Bei einem 3D-Array mit ~ 8 GB dauerte das Lesen eines "vollständigen" Slice entlang einer beliebigen Achse mit einem HDF5-Datensatz ~ 20 Sekunden und bis zu 0,3 Sekunden (Best-Case) über drei Stunden (Worst-Case) ein memmapped Array der gleichen Daten.

Abgesehen von den oben aufgeführten Dingen bietet ein "Chunked" * -Datenformat auf der Festplatte wie HDF5 einen weiteren großen Vorteil: Das Lesen eines beliebigen Slice (Schwerpunkt auf Beliebig) ist in der Regel viel schneller, da die Daten auf der Festplatte zusammenhängender sind durchschnittlich.

*(HDF5 muss kein Chunked-Datenformat sein. Es unterstützt Chunking, erfordert es jedoch nicht. Tatsächlich ist dies die Standardeinstellung zum Erstellen eines Datasets in h5py kein Chunk, wenn ich mich richtig erinnere.)

Grundsätzlich liegt Ihre Best-Case-Lesegeschwindigkeit für Festplatten und Ihre Worst-Case-Festplattenlesegeschwindigkeit für ein bestimmtes Segment Ihres Datasets ziemlich nahe an einem HDF-Chunked-Dataset (vorausgesetzt, Sie haben eine angemessene Chunk-Größe gewählt oder lassen eine Bibliothek eine für Sie auswählen). Mit einem einfachen binären Array ist der beste Fall schneller, der schlechteste jedoch viel schlechter.

Eine Einschränkung: Wenn Sie eine SSD haben, werden Sie wahrscheinlich keinen großen Unterschied in der Lese- / Schreibgeschwindigkeit bemerken. Bei einer normalen Festplatte sind sequentielle Lesevorgänge jedoch viel, viel schneller als zufällige Lesevorgänge. (dh eine normale Festplatte hat eine lange seekZeit.) HDF hat auf einer SSD immer noch einen Vorteil, aber es liegt mehr an den anderen Funktionen (z. B. Metadaten, Organisation usw.) als an der Geschwindigkeit.


h5pyUm Verwirrung zu beseitigen, gibt der Zugriff auf ein Dataset zunächst ein Objekt zurück, das sich einem Numpy-Array ziemlich ähnlich verhält, die Daten jedoch erst in den Speicher lädt, wenn sie in Scheiben geschnitten sind. (Ähnlich wie memmap, jedoch nicht identisch.) Weitere Informationen finden Sie in der h5pyEinführung .

Durch das Schneiden des Datasets wird eine Teilmenge der Daten in den Speicher geladen, aber vermutlich möchten Sie etwas damit tun. An diesem Punkt benötigen Sie sie ohnehin im Speicher.

Wenn Sie Out-of-Core-Berechnungen durchführen möchten, können Sie relativ einfach tabellarische Daten mit pandasoder abrufen pytables. Es ist möglich mit h5py(besser für große ND-Arrays), aber Sie müssen auf eine niedrigere Ebene fallen und die Iteration selbst durchführen.

Die Zukunft von numpy-ähnlichen Out-of-Core-Berechnungen ist jedoch Blaze. Schauen Sie sich das an, wenn Sie diesen Weg wirklich einschlagen möchten.


Der "unbekannte" Fall

Betrachten Sie zunächst ein 3D-Array in C-Reihenfolge, das auf die Festplatte geschrieben wurde (ich simuliere es, indem ich arr.ravel()das Ergebnis aufrufe und drucke, um die Sichtbarkeit zu verbessern):

In [1]: import numpy as np

In [2]: arr = np.arange(4*6*6).reshape(4,6,6)

In [3]: arr
Out[3]:
array([[[  0,   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, 133, 134, 135, 136, 137],
        [138, 139, 140, 141, 142, 143]]])

Die Werte werden nacheinander auf der Festplatte gespeichert, wie in Zeile 4 unten gezeigt. (Lassen Sie uns die Details und die Fragmentierung des Dateisystems für den Moment ignorieren.)

In [4]: arr.ravel(order='C')
Out[4]:
array([  0,   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, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143])

Nehmen wir im besten Fall ein Stück entlang der ersten Achse. Beachten Sie, dass dies nur die ersten 36 Werte des Arrays sind. Dies wird eine sehr schnelle Lektüre sein! (man sucht, man liest)

In [5]: arr[0,:,:]
Out[5]:
array([[ 0,  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]])

In ähnlicher Weise sind die nächsten 36 Werte nur die nächste Schicht entlang der ersten Achse. Um einen vollständigen Schnitt entlang dieser Achse zu lesen, benötigen wir nur eine seekOperation. Wenn wir nur verschiedene Schnitte entlang dieser Achse lesen wollen, ist dies die perfekte Dateistruktur.

Betrachten wir jedoch das Worst-Case-Szenario: Ein Slice entlang der letzten Achse.

In [6]: arr[:,:,0]
Out[6]:
array([[  0,   6,  12,  18,  24,  30],
       [ 36,  42,  48,  54,  60,  66],
       [ 72,  78,  84,  90,  96, 102],
       [108, 114, 120, 126, 132, 138]])

Zum Einlesen dieses Slice benötigen wir 36 Suchvorgänge und 36 Lesevorgänge, da alle Werte auf der Festplatte getrennt sind. Keiner von ihnen ist benachbart!

Dies mag ziemlich geringfügig erscheinen, aber wenn wir zu immer größeren Arrays kommen, seekwächst die Anzahl und Größe der Operationen schnell. Für ein großes (~ 10 GB) 3D-Array, das auf diese Weise gespeichert und über eingelesen wirdmemmap , kann das Lesen eines vollständigen Slice entlang der "schlechtesten" Achse selbst mit moderner Hardware problemlos mehrere zehn Minuten dauern. Gleichzeitig kann ein Schnitt entlang der besten Achse weniger als eine Sekunde dauern. Der Einfachheit halber zeige ich nur "vollständige" Slices entlang einer einzelnen Achse, aber genau das gleiche passiert mit beliebigen Slices einer beliebigen Teilmenge der Daten.

Übrigens gibt es mehrere Dateiformate, die dies nutzen und im Grunde drei Kopien großer 3D-Arrays auf der Festplatte speichern: eine in C-Reihenfolge, eine in F-Reihenfolge und eine in der Zwischenstufe zwischen beiden. (Ein Beispiel hierfür ist das D3D-Format von Geoprobe, obwohl ich nicht sicher bin, ob es irgendwo dokumentiert ist.) Wen interessiert es, wenn die endgültige Dateigröße 4 TB beträgt, ist Speicherplatz billig! Das Verrückte daran ist, dass die Lesevorgänge, die Sie ausführen möchten, sehr, sehr schnell sind, da der Hauptanwendungsfall darin besteht, ein einzelnes Sub-Slice in jede Richtung zu extrahieren. Es funktioniert sehr gut!


Der einfache "Chunked" Fall

Angenommen, wir speichern 2x2x2 "Chunks" des 3D-Arrays als zusammenhängende Blöcke auf der Festplatte. Mit anderen Worten, so etwas wie:

nx, ny, nz = arr.shape
slices = []
for i in range(0, nx, 2):
    for j in range(0, ny, 2):
        for k in range(0, nz, 2):
            slices.append((slice(i, i+2), slice(j, j+2), slice(k, k+2)))

chunked = np.hstack([arr[chunk].ravel() for chunk in slices])

Die Daten auf der Festplatte würden also so aussehen chunked:

array([  0,   1,   6,   7,  36,  37,  42,  43,   2,   3,   8,   9,  38,
        39,  44,  45,   4,   5,  10,  11,  40,  41,  46,  47,  12,  13,
        18,  19,  48,  49,  54,  55,  14,  15,  20,  21,  50,  51,  56,
        57,  16,  17,  22,  23,  52,  53,  58,  59,  24,  25,  30,  31,
        60,  61,  66,  67,  26,  27,  32,  33,  62,  63,  68,  69,  28,
        29,  34,  35,  64,  65,  70,  71,  72,  73,  78,  79, 108, 109,
       114, 115,  74,  75,  80,  81, 110, 111, 116, 117,  76,  77,  82,
        83, 112, 113, 118, 119,  84,  85,  90,  91, 120, 121, 126, 127,
        86,  87,  92,  93, 122, 123, 128, 129,  88,  89,  94,  95, 124,
       125, 130, 131,  96,  97, 102, 103, 132, 133, 138, 139,  98,  99,
       104, 105, 134, 135, 140, 141, 100, 101, 106, 107, 136, 137, 142, 143])

Und um zu zeigen, dass es sich um 2x2x2 Blöcke handelt arr, beachten Sie, dass dies die ersten 8 Werte von chunked:

In [9]: arr[:2, :2, :2]
Out[9]:
array([[[ 0,  1],
        [ 6,  7]],

       [[36, 37],
        [42, 43]]])

Um einen Slice entlang einer Achse einzulesen, haben wir entweder 6 oder 9 zusammenhängende Blöcke eingelesen (doppelt so viele Daten wie wir benötigen) und dann nur den gewünschten Teil beibehalten. Dies ist ein Worst-Case-Maximum von 9 Suchvorgängen gegenüber einem Maximum von 36 Suchvorgängen für die nicht blockierte Version. (Der beste Fall sind jedoch immer noch 6 Suchvorgänge gegenüber 1 Suchvorgängen für das Memmapped-Array.) Da sequentielle Lesevorgänge im Vergleich zu Suchvorgängen sehr schnell sind, wird die Zeit zum Lesen einer beliebigen Teilmenge in den Speicher erheblich reduziert. Dieser Effekt wird bei größeren Arrays erneut größer.

HDF5 geht noch ein paar Schritte weiter. Die Chunks müssen nicht zusammenhängend gespeichert werden und werden von einem B-Tree indiziert. Darüber hinaus müssen sie auf der Festplatte nicht dieselbe Größe haben, sodass die Komprimierung auf jeden Block angewendet werden kann.


Chunked Arrays mit h5py

Standardmäßig werden h5pykeine HDF-Dateien auf der Festplatte erstellt ( pytablesim Gegensatz dazu glaube ich ). Wenn Sie chunks=Truebeim Erstellen des Datasets angeben , wird jedoch ein Blockarray auf der Festplatte angezeigt.

Als schnelles, minimales Beispiel:

import numpy as np
import h5py

data = np.random.random((100, 100, 100))

with h5py.File('test.hdf', 'w') as outfile:
    dset = outfile.create_dataset('a_descriptive_name', data=data, chunks=True)
    dset.attrs['some key'] = 'Did you want some metadata?'

Beachten Sie, dass chunks=Trueerzählt h5pyeine Blockgröße für uns automatisch zu holen. Wenn Sie mehr über Ihren häufigsten Anwendungsfall wissen, können Sie die Blockgröße / -form optimieren, indem Sie ein Formtupel angeben (z. B. (2,2,2)im obigen einfachen Beispiel). Auf diese Weise können Sie Lesevorgänge entlang einer bestimmten Achse effizienter gestalten oder für Lese- / Schreibvorgänge einer bestimmten Größe optimieren.


Vergleich der E / A-Leistung

Um den Punkt zu betonen, vergleichen wir das Lesen in Slices aus einem HDF5-Datensatz und einem großen (~ 8 GB) 3D-Array in Fortran-Reihenfolge, das genau dieselben Daten enthält.

Ich habe zwischen jedem Lauf alle Betriebssystem-Caches geleert, daher sehen wir die "kalte" Leistung.

Für jeden Dateityp testen wir das Einlesen eines "vollständigen" X-Slice entlang der ersten Achse und eines "vollständigen" Z-Slize entlang der letzten Achse. Für das von Fortran geordnete memmapped-Array ist der Slice "x" der schlechteste Fall und der Slice "z" der beste Fall.

Der verwendete Code befindet sich in einem Kern (einschließlich der Erstellung der hdfDatei). Ich kann die hier verwendeten Daten nicht einfach freigeben, aber Sie können sie durch ein Array von Nullen derselben Form ( 621, 4991, 2600)und demselben Typ) simulieren np.uint8.

Das chunked_hdf.pysieht so aus:

import sys
import h5py

def main():
    data = read()

    if sys.argv[1] == 'x':
        x_slice(data)
    elif sys.argv[1] == 'z':
        z_slice(data)

def read():
    f = h5py.File('/tmp/test.hdf5', 'r')
    return f['seismic_volume']

def z_slice(data):
    return data[:,:,0]

def x_slice(data):
    return data[0,:,:]

main()

memmapped_array.pyist ähnlich, hat aber einen Hauch mehr Komplexität, um sicherzustellen, dass die Slices tatsächlich in den Speicher geladen werden (standardmäßig wird ein anderes memmappedArray zurückgegeben, was kein Vergleich von Äpfeln zu Äpfeln wäre).

import numpy as np
import sys

def main():
    data = read()

    if sys.argv[1] == 'x':
        x_slice(data)
    elif sys.argv[1] == 'z':
        z_slice(data)

def read():
    big_binary_filename = '/data/nankai/data/Volumes/kumdep01_flipY.3dv.vol'
    shape = 621, 4991, 2600
    header_len = 3072

    data = np.memmap(filename=big_binary_filename, mode='r', offset=header_len,
                     order='F', shape=shape, dtype=np.uint8)
    return data

def z_slice(data):
    dat = np.empty(data.shape[:2], dtype=data.dtype)
    dat[:] = data[:,:,0]
    return dat

def x_slice(data):
    dat = np.empty(data.shape[1:], dtype=data.dtype)
    dat[:] = data[0,:,:]
    return dat

main()

Schauen wir uns zuerst die HDF-Leistung an:

jofer at cornbread in ~ 
$ sudo ./clear_cache.sh

jofer at cornbread in ~ 
$ time python chunked_hdf.py z
python chunked_hdf.py z  0.64s user 0.28s system 3% cpu 23.800 total

jofer at cornbread in ~ 
$ sudo ./clear_cache.sh

jofer at cornbread in ~ 
$ time python chunked_hdf.py x
python chunked_hdf.py x  0.12s user 0.30s system 1% cpu 21.856 total

Ein "vollständiger" x-Slice und ein "vollständiger" z-Slice benötigen ungefähr die gleiche Zeit (~ 20 Sekunden). Wenn man bedenkt, dass es sich um ein 8-GB-Array handelt, ist das nicht schlecht. Meistens

Und wenn wir dies mit den memmapped Array-Zeiten vergleichen (es ist Fortran-geordnet: Ein "Z-Slice" ist der beste Fall und ein "X-Slice" ist der schlechteste Fall.):

jofer at cornbread in ~ 
$ sudo ./clear_cache.sh

jofer at cornbread in ~ 
$ time python memmapped_array.py z
python memmapped_array.py z  0.07s user 0.04s system 28% cpu 0.385 total

jofer at cornbread in ~ 
$ sudo ./clear_cache.sh

jofer at cornbread in ~ 
$ time python memmapped_array.py x
python memmapped_array.py x  2.46s user 37.24s system 0% cpu 3:35:26.85 total

Ja, das hast du richtig gelesen. 0,3 Sekunden für eine Schnittrichtung und ~ 3,5 Stunden für die andere.

Die Zeit zum Schneiden in "x" -Richtung ist weitaus länger als die Zeit, die benötigt wird, um das gesamte 8-GB-Array in den Speicher zu laden und das gewünschte Segment auszuwählen! (Auch dies ist ein Array mit Fortran-Ordnung. Das entgegengesetzte x / z-Slice-Timing wäre für ein Array mit C-Ordnung der Fall.)

Wenn wir jedoch immer einen Slice entlang der Best-Case-Richtung machen möchten, ist das große binäre Array auf der Festplatte sehr gut. (~ 0,3 Sek!)

Bei einem Memmapped-Array bleibt diese E / A-Diskrepanz bestehen (oder vielleicht ist Anisotropie ein besserer Begriff). Bei einem Chunked-HDF-Dataset können Sie die Chunksize jedoch so auswählen, dass der Zugriff entweder gleich ist oder für einen bestimmten Anwendungsfall optimiert ist. Es gibt Ihnen viel mehr Flexibilität.

Zusammenfassend

Hoffentlich hilft das jedenfalls dabei, einen Teil Ihrer Frage zu klären. HDF5 hat viele andere Vorteile gegenüber "rohen" Memmaps, aber ich habe hier keinen Raum, um alle zu erweitern. Die Komprimierung kann einige Dinge beschleunigen (die Daten, mit denen ich arbeite, profitieren nicht sehr von der Komprimierung, daher verwende ich sie selten), und das Zwischenspeichern auf Betriebssystemebene wird mit HDF5-Dateien häufig besser abgespielt als mit "rohen" Memmaps. Darüber hinaus ist HDF5 ein wirklich fantastisches Containerformat. Es bietet Ihnen viel Flexibilität bei der Verwaltung Ihrer Daten und kann in mehr oder weniger jeder Programmiersprache verwendet werden.

Probieren Sie es insgesamt aus und prüfen Sie, ob es für Ihren Anwendungsfall gut funktioniert. Ich denke, Sie könnten überrascht sein.


3
Gute Antwort. Ich möchte hinzufügen, dass Sie Ihr Chunking-Layout an Ihr typisches Datenzugriffsmuster anpassen können. Wenn Ihr Zugriffsmuster eine ziemlich vorhersehbare Schablonengröße hat, können Sie in der Regel Ihren Chunking so wählen, dass jederzeit eine nahezu optimale Geschwindigkeit erreicht wird.
Eelco Hoogendoorn

2
Gute Antwort! Eine Sache, die beim Chunking nicht erwähnt wird, ist der Effekt des Chunk-Cache. Jedes geöffnete Dataset verfügt über einen eigenen Chunk-Cache, dessen Standardgröße 1 MB beträgt und der mit H5Pset_chunk_cache () in C angepasst werden kann. Es ist im Allgemeinen hilfreich zu berücksichtigen, wie viele Chunks im Speicher gespeichert werden können, wenn Sie über Ihre Zugriffsmuster nachdenken. Wenn Ihr Cache beispielsweise 8 Blöcke aufnehmen kann und Ihr Datensatz 10 Blöcke in Richtung des Scans enthält, werden Sie viel verprügeln und die Leistung wird schrecklich sein.
Dana Robinson
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.