Ich muss einige Daten verarbeiten, die ein paar hundert Mal größer sind als RAM. Ich möchte in einem großen Stück lesen, verarbeiten, speichern Sie das Ergebnis, befreien Sie die Erinnerung und wiederholen. Gibt es eine Möglichkeit, dies in Python effizient zu machen?
Der allgemeine Schlüssel ist, dass Sie die Datei iterativ verarbeiten möchten.
Wenn Sie nur mit einer Textdatei arbeiten, ist das trivial: for line in f:
liest nur jeweils eine Zeile. (Tatsächlich puffert es die Dinge auf, aber die Puffer sind klein genug, dass Sie sich keine Gedanken darüber machen müssen.)
Wenn Sie mit einem anderen spezifischen Dateityp arbeiten, z. B. mit einer nackten Binärdatei, einer CSV-Datei, einem XML-Dokument usw., gibt es im Allgemeinen ähnliche Speziallösungen, aber niemand kann sie Ihnen beschreiben, es sei denn Sie sagen Sie uns, welche Art von Daten Sie haben.
Aber was ist, wenn Sie eine allgemeine Binärdatei haben?
Erstens, die read
-Methode verwendet optionale max-Bytes lesen. Also statt dessen:
Sie können dies tun:
%Vor%Sie können stattdessen eine Funktion wie folgt schreiben:
%Vor%Dann können Sie das einfach tun:
%Vor% Sie könnten dies auch mit dem zwei-Argument iter
machen, aber viele Leute finden das ein bisschen unklar:
Wie auch immer, diese Option gilt für alle anderen unten aufgeführten Varianten (außer für ein einzelnes mmap
, was so trivial ist, dass es keinen Sinn ergibt).
Es gibt nichts Magisches an der Nummer 8192 dort. Im Allgemeinen möchten Sie eine Potenz von 2 und idealerweise ein Vielfaches der Seitengröße Ihres Systems. Darüber hinaus variiert Ihre Leistung nicht so sehr, unabhängig davon, ob Sie 4KB oder 4MB verwenden. Wenn dies der Fall ist, müssen Sie testen, was für Ihren Anwendungsfall am besten geeignet ist.
Wie auch immer, dies setzt voraus, dass Sie nur jede 8K gleichzeitig verarbeiten können, ohne irgendeinen Kontext einzuhalten. Wenn Sie z. B. Daten in einen Progressive Decoder oder Hasher oder etwas einspeisen, ist das perfekt.
Wenn Sie jedoch einen "Chunk" gleichzeitig verarbeiten müssen, könnten Ihre Chunks über eine 8-KB-Grenze hinausreichen. Wie gehst du damit um?
Es hängt davon ab, wie Ihre Chunks in der Datei abgegrenzt sind, aber die Grundidee ist ziemlich einfach. Angenommen, Sie verwenden NUL-Bytes als Trennzeichen (nicht sehr wahrscheinlich, aber einfach als Spielzeugbeispiel zu zeigen).
%Vor% Diese Art von Code ist im Netzwerk sehr verbreitet (weil sockets
nicht nur "alles lesen" kann, also müssen Sie immer in einen Puffer lesen und In den Nachrichten können Sie einige nützliche Beispiele finden, die einen ähnlichen Code wie Ihr Dateiformat verwenden.
Alternativ können Sie mmap
verwenden.
Wenn Ihre virtuelle Speichergröße größer ist als die Datei, ist das trivial:
%Vor% Jetzt verhält sich m
wie ein riesiges bytes
-Objekt, genau so, als hätten Sie read()
aufgerufen, um das Ganze in den Speicher zu schreiben - aber das Betriebssystem puffert bei Bedarf automatisch Bits in und aus dem Speicher.
Wenn Sie versuchen, eine Datei zu lesen, die zu groß für Ihre virtuelle Speichergröße ist (z. B. eine 4-GB-Datei mit 32-Bit-Python oder eine 20EB-Datei mit 64-Bit-Python) 2013, wenn Sie eine spärliche oder virtuelle Datei lesen, sagen wir, die VM-Datei für einen anderen Prozess unter Linux), müssen Sie windowing-mmap in einem Teil der Datei gleichzeitig implementieren. Zum Beispiel:
%Vor%Natürlich hat das Mapping-Fenster das gleiche Problem wie das Lesen von Chunks, wenn Sie Dinge abgrenzen müssen, und Sie können es auf die gleiche Weise lösen.
Aber als Optimierung können Sie statt der Pufferung das Fenster einfach auf die Seite mit dem Ende der letzten vollständigen Nachricht schieben, anstatt auf 8 MB gleichzeitig, und dann können Sie das Kopieren vermeiden. Dies ist ein wenig komplizierter. Wenn Sie es also tun wollen, suchen Sie nach etwas wie "sliding mmap window" und schreiben Sie eine neue Frage, wenn Sie nicht weiterkommen.
Tags und Links python