2010-08-19 6 views
13

Ich speichere eine Tabelle mit Python und ich brauche Persistenz.Shelve ist zu langsam für große Wörterbücher. Was kann ich tun, um die Leistung zu verbessern?

Im Wesentlichen speichern ich die Tabelle als Wörterbuch-String zu Zahlen. Und wird die gesamte gespeicherte mit shelve

self.DB=shelve.open("%s%sMoleculeLibrary.shelve"%(directory,os.sep),writeback=True) 

Ich benutze writeback-True wie ich das System gefunden, instabil zu sein neigt, wenn ich dies nicht tun.

Nach den Berechnungen muss das System die Datenbank schließen und speichern. Jetzt ist die Datenbank (die Tabelle) ungefähr 540 MB groß und dauert ewig. Die Zeit explodierte, nachdem der Tisch auf etwa 500 MB angewachsen war. Aber ich brauche einen viel größeren Tisch. Tatsächlich brauche ich zwei von ihnen.

Ich verwende wahrscheinlich die falsche Form der Persistenz. Was kann ich tun, um die Leistung zu verbessern?

+0

Haben Sie eine unzureichende CPU-Auslastung mit großen Einschränkungen bei der Verwendung von Regalen festgestellt? –

Antwort

13

Zum Speichern eines umfangreichen Wörterbuchs mit Schlüssel/Wert-Paaren string : number empfehle ich eine JSON-native Speicherlösung wie MongoDB. Es hat eine wunderbare API für Python, Pymongo. MongoDB selbst ist leichtgewichtig und unglaublich schnell, und Json-Objekte werden nativ Wörterbücher in Python sein. Dies bedeutet, dass Sie Ihren Schlüssel string als Objekt-ID verwenden können, um komprimierten Speicher und schnelle Suche zu ermöglichen.

Als Beispiel dafür, wie leicht wäre der Code finden Sie in der folgenden:

d = {'string1' : 1, 'string2' : 2, 'string3' : 3} 
from pymongo import Connection 
conn = Connection() 
db = conn['example-database'] 
collection = db['example-collection'] 
for string, num in d.items(): 
    collection.save({'_id' : string, 'value' : num}) 
# testing 
newD = {} 
for obj in collection.find(): 
    newD[obj['_id']] = obj['value'] 
print newD 
# output is: {u'string2': 2, u'string3': 3, u'string1': 1} 

Sie müssten nur von Unicode umwandeln zurück, die trivial ist.

+0

Danke. Die Daten sind eigentlich eine symmetrische Tabellennummer * number -> number, aber da shelve gewünschte Strings als Schlüssel wollte, wurde ich irgendwie dazu gebracht, sie als Tabellenstring zu schreiben -> Zahl, wobei die Zeichenkette "a_b" mit a und b ist Zahlen und a

1

Wie viel größer? Was sind die Zugriffsmuster? Welche Art von Berechnungen müssen Sie darauf durchführen?

Denken Sie daran, dass Sie einige Leistungsgrenzen haben werden, wenn Sie die Tabelle nicht im Speicher behalten können, egal wie Sie es tun.

Sie können sehen, gehen zu SQLAlchemy, oder direkt mit etwas wie bsddb, aber beide von denen wird die Einfachheit des Codes zu opfern. Mit SQL können Sie jedoch einen Teil der Arbeit abhängig von der Arbeitslast auf die Datenbankebene verlagern.

+2

Ich entwickle einen theoretischen Algorithmus, so dass das Problem, das ich jetzt verwende, wahrscheinlich Tabellen von einigen Giga hat. Aber da die Leute den Algorithmus für andere Probleme verwenden (hauptsächlich in der Systembiologie, denken Sie groß, dann erhöhen Sie), ist es wichtig, eine Lösung zu finden, die sich vergrößern kann. Der Zugriff ist zufällig und auf jeden Begriff wird einige Male zugegriffen. Die einzige Berechnung, die ich machen muss, ist, den Wert zu erhalten, den Wert zu berechnen, wenn er nicht vorhanden ist, und ihn zu speichern. Ich überlegte, MySQL zu verwenden, damit die DB nicht im Speicher war. Aber es würde den Code komplexer und langsamer machen. Vielen Dank. –

9

Basierend auf meiner Erfahrung, würde ich empfehlen, SQLite3, die mit Python kommt. Es funktioniert gut mit größeren Datenbanken und Schlüsselnummern. Millionen von Schlüsseln und Gigabytes an Daten sind kein Problem. Shelve ist an diesem Punkt total verschwendet. Auch ein getrennter db-Prozess ist nicht vorteilhaft, es erfordert nur mehr Kontext-Swaps. In meinen Tests stellte ich fest, dass SQLite3 die bevorzugte Option war, um lokal größere Datenmengen zu verarbeiten. Das Ausführen einer lokalen Datenbank-Engine wie mongo, mysql oder postgresql bietet keinen zusätzlichen Wert und war auch langsamer.

0

Ich denke, dein Problem ist aufgrund der Tatsache, dass Sie die writeback=True verwenden. Die documentation sagt (Schwerpunkt ist von mir):

Wegen Python Semantik kann ein Regal nicht wissen, wann ein veränderlicher persistent-Wörterbuch-Eintrag geändert wird. Standardmäßig werden geänderte Objekte nur geschrieben, wenn sie dem Regal zugewiesen sind (siehe Beispiel).Wenn der optionale Rückschreibparameter auf True gesetzt ist, werden alle aufgerufenen Einträge ebenfalls im Speicher zwischengespeichert und bei sync() und close() zurückgeschrieben. Dieses kann es leichter machen, änderbare Einträge im persistenten Wörterbuch zu ändern, aber wenn auf viele Einträge zugegriffen wird, kann es riesige Speichermengen für den Cache verbrauchen, und kann es die Schließoperation sehr langsam seit alle Zugriffe machen Einträge werden zurückgeschrieben (es gibt keine Möglichkeit zu bestimmen, welche zugegriffen Einträge sind veränderbar, noch welche waren tatsächlich mutiert).

Sie vermeiden konnte nur einmal writeback=True und stellen Sie sicher, dass die Daten geschrieben werden, mit (Sie müssen darauf achten, dass nachträgliche Änderungen verloren gehen werden).

Wenn Sie glauben, dies ist nicht die richtige Speicheroption (es ist schwer zu sagen, ohne zu wissen, wie die Daten strukturiert sind), schlage ich sqlite3 vor, es ist in Python integriert (also sehr portabel) und hat sehr schöne Leistungen. Es ist etwas komplizierter als ein einfacher Schlüssel-Wert-Speicher.

Siehe andere Antworten für Alternativen.

Verwandte Themen