effiziente Möglichkeit, ein großes Diktat im Speicher von Python zu speichern und zu verarbeiten

8

Wie ich ein bisschen Test gemacht habe, kann ein Python-Diktat von int = & gt; int (unterschiedlicher Wert) von 30 Millionen Elementen leicht & gt; 2G Speicher auf meinem Mac essen. Da ich nur mit int int dict arbeite, gibt es eine bessere Lösung als python dict?

Einige Anforderungen, die ich brauche, sind

  1. mehr Speicher effizient beim Halten Dutzende von Millionen Ebene von int zu int Elemente
  2. grundlegende dict-Methoden wie Wert durch Schlüssel abrufen und alle Elemente iterieren
  3. einfach zu serialisieren / binary wäre ein Plus

Aktualisierung,  4. leicht zu erhalten Teilmenge von bestimmten Tasten, wie d.fromkeys ([...])

Danke.

    
Jason Xu 04.08.2013, 10:13
quelle

4 Antworten

2

Judy-Array-basierte Lösung scheint die Option, die ich untersuchen sollte. Ich bin immer noch auf der Suche nach einer guten Implementierung, die von Python verwendet werden kann. Wird später aktualisiert.

Aktualisieren,

Ich experimentiere schließlich mit einem Judy-Array-Wrapper bei Ссылка . Scheint kein Dokument dort, aber ich habe versucht, seine Methoden einfach durch dir (...) sein Paket und Objekt, aber es funktioniert.

Gleiches Experiment es isst ~ 986MB bei ~ 1/3 des Standarddikts, indem es judy.JudyIntObjectMap verwendet. Es stellt auch JudyIntSet zur Verfügung, das in einem speziellen Szenario viel mehr Speicher speichert, da es im Vergleich zu JudyIntObjectMap nicht auf ein echtes Python-Objekt als Wert verweisen muss.

(Wie weiter unten beschrieben, verwendet JudyArray einfach mehrere MB bis zu zehn MB, die meisten von ~ 986 MB werden tatsächlich von Wertobjekten in Python-Speicherplatz verwendet.)

Hier ist ein Code, wenn es dir hilft,

%Vor%

Aktualisieren,

ok, ein JudyIntSet von 30M int wie getestet.

%Vor%

Es verwendet nur 5.7MB, um 30M sequenzielles int-Array [0,30000000) zu speichern, was aufgrund der automatischen Komprimierung von JudyArray möglich ist. Über 709 MB ist bcz Ich habe Bereich (...) statt richtiger xrange (...) verwendet, um die Daten zu generieren.

Die Größe des JudyArray Kerns mit 30M int ist einfach ignorierbar.

Wenn jemand eine vollständigere Judy Array-Wrapper-Implementierung kennt, lassen Sie es mich wissen, da dieser Wrapper nur JudyIntObjectMap und JudyIntSet umschließt. Für int-int dict benötigt JudyIntObjectMap immer noch ein echtes Python-Objekt. Wenn wir nur counter_add verwenden und die Werte festlegen, wäre es eine gute Idee, int von Werten im C-Space zu speichern, anstatt das Python-Objekt zu verwenden. Hoffe jemand ist daran interessiert, einen zu erstellen oder einzuführen:)

    
Jason Xu 04.08.2013, 11:23
quelle
6

Es gibt mindestens zwei Möglichkeiten:

Arrays

Sie könnten versuchen, zwei Arrays zu verwenden. Eine für die Schlüssel und eine für die Werte, so dass index (key) == index (value)

Aktualisiert 2017-01-05: verwendet 4-Byte-Ganzzahlen im Array.

Ein Array würde weniger Speicher benötigen. Auf einem 64-Bit-FreeBSD-Rechner mit Python, der mit Clang kompiliert wurde, verwendet ein Array von 30 Millionen Ganzzahlen etwa 117 MiB.

Dies sind die Python-Befehle, die ich verwendet habe:

%Vor%

Nach dem Importieren des Arrays meldet ps :

%Vor%

Nach dem Erstellen des Arrays:

%Vor%

Die Resident-Set-Größe wird in 1 KiB-Einheiten angegeben, also (128776 - 8100) / 1024 = 117 MiB

Mit List Comprehensions können Sie leicht eine Liste von Indizes erhalten, wo der Schlüssel eine bestimmte Bedingung erfüllt. Sie können dann die Indizes in dieser Liste verwenden, um auf die entsprechenden Werte zuzugreifen ...

numpy

Wenn Sie mehr als genug zur Verfügung haben, ist das schneller, hat mehr Funktionen und benötigt etwas weniger RAM:

%Vor%

Von ps : 6700 KiB nach dem Start von Python, 17400 KiB nach dem Import von numpy und 134824 KiB nach dem Erstellen des Arrays. Das sind etwa 114 MiB.

Darüber hinaus unterstützt numpy Array-Arrays ;

%Vor%

Hier können Sie separat auf die Schlüssel und Werte zugreifen;

%Vor%     
Roland Smith 04.08.2013 10:44
quelle
1

Wenn wir ein bisschen mehr darüber wüssten, wie es verwendet wird, könnte es einfacher sein, gute Lösungen vorzuschlagen. Sie sagen, Sie möchten Werte per Schlüssel abrufen und über alle von ihnen iterieren, aber nichts darüber, ob Sie Daten einfügen / löschen müssen.

Eine ziemlich effiziente Methode zum Speichern von Daten ist das Array -Modul. Wenn Sie keine Daten einfügen / entfernen müssen, könnten Sie einfach zwei Arrays haben. Das "Schlüssel" -Array würde sortiert und Sie könnten eine Binärsuche für den richtigen Schlüssel durchführen. Dann würden Sie einfach den Wert von der gleichen Position in dem anderen Array auswählen.

Sie könnten das in einer Klasse, die sich dict-like verhält, leicht einkapseln. Ich weiß nicht, ob es dafür irgendwo eine fertige Lösung gibt, aber es sollte nicht so schwer zu implementieren sein. Das sollte dir helfen, viele Python-Objekte zu vermeiden, die Speicher verbrauchen.

Aber Sie könnten andere Anforderungen haben, die eine solche Lösung unpraktisch / unmöglich machen.

    
Mattias Nilsson 04.08.2013 10:43
quelle
1

Eine weitere Antwort wurde hinzugefügt, wenn Sie nur einen wörterbuchähnlichen Zähler suchen, der einfach zu verwenden ist.

Hochleistungs-Counter-Objekt aus der Python-Standardbibliothek

    
Jason Xu 15.08.2013 08:13
quelle

Tags und Links