Wie Berechnung vermeiden jedes Mal, wenn ein Python-Modul neu geladen werden

StackOverflow https://stackoverflow.com/questions/195626

  •  10-07-2019
  •  | 
  •  

Frage

ich eine Python-Modul habe, die Verwendung einer großen Wörterbuch globalen Variablen macht, zur Zeit ich die Berechnung Code im oberen Bereich setzte, findet jeder erstes Mal Import oder Neuladen des Moduls mehr als eine Minute, die völlig inakzeptabel ist. Wie kann ich das Berechnungsergebnis irgendwo speichern, so dass das nächste Import / Neuladen nicht zu berechnen hat? Ich habe versucht, cPickle, aber ungefähr zur gleichen Zeit wie die Berechnung nimmt das Wörterbuch Variable aus einer Datei (1,3 M) geladen werden.

Für weitere Informationen über mein Problem geben,

FD = FreqDist(word for word in brown.words()) # this line of code takes 1 min
War es hilfreich?

Lösung

Nur um zu klären: der Code in dem Körper eines Moduls ist nicht jedes Mal ausgeführt das Modul importiert wird - es wird nur einmal ausgeführt, wonach finden zukünftige Importe die bereits Modul erstellt, anstatt Neuer es. Werfen Sie einen Blick auf sys.modules die Liste der im Cache gespeicherten Module zu sehen.

Allerdings, wenn Ihr Problem ist die Zeit, es zum ersten Import erfolgt, nachdem das Programm ausgeführt wird, müssen Sie wahrscheinlich eine andere Methode als eine Python dict verwenden. Wahrscheinlich wäre am besten, ein On-Disk-Formular zu verwenden, zum Beispiel eine SQLite-Datenbank, einer der dbm-Module.

Für eine minimale Änderung in Ihrer Schnittstelle, die shelve Modul der beste Option sein kann - dies setzt eine recht transparente Schnittstelle zwischen der dbm-Module, die sie wie ein beliebigen Python dict handeln macht, so dass jeder picklable Wert gespeichert werden. Hier ein Beispiel:

# Create dict with a million items:
import shelve
d = shelve.open('path/to/my_persistant_dict')
d.update(('key%d' % x, x) for x in xrange(1000000))
d.close()

Dann im nächsten Prozess, verwenden Sie es. Es sollte keine große Verzögerung, da Lookups nur für die auf der On-Disk-Form angeforderten Schlüssel durchgeführt werden, so dass alles muss nicht in den Speicher geladen werden:

>>> d = shelve.open('path/to/my_persistant_dict')
>>> print d['key99999']
99999

Es ist ein bisschen langsamer als eine echte dict, und es noch lange dauern zu laden, wenn Sie etwas tun, das alle Schlüssel erfordert (z. B. versuchen, es zu drucken), kann aber lösen Ihr Problem.

Andere Tipps

Berechnen Sie Ihre globale var auf dem ersten Gebrauch.

class Proxy:
    @property
    def global_name(self):
        # calculate your global var here, enable cache if needed
        ...

_proxy_object = Proxy()
GLOBAL_NAME = _proxy_object.global_name

Oder noch besser, Zugang necessery Daten über spezielles Datenobjekt.

class Data:
    GLOBAL_NAME = property(...)

data = Data()

Beispiel:

from some_module import data

print(data.GLOBAL_NAME)

Siehe Django Einstellungen .

Ich gehe davon aus Sie die dict in die Quelle wörtlichen eingefügt haben, und das ist, was eine Minute zu nehmen? Ich weiß nicht, wie um das zu bekommen, aber Sie könnten wahrscheinlich vermeiden diese dict Instanziieren auf Import ... Sie könnten lazily-instanziiert es das erste Mal ist es tatsächlich verwendet wird.

Sie könnten versuchen, die Verwendung von Marschall Modul anstelle der c ? Pickle ein; es könnte schneller sein. Dieses Modul wird von Python zu speichern Werte in einem binären Format verwendet. Beachten Sie vor allem den folgenden Absatz, um zu sehen, ob Marschall Ihren Bedürfnissen entspricht:

  

Nicht alle Python-Objekttypen werden unterstützt; in der Regel werden nur Objekte, deren Wert unabhängig von einem bestimmten Aufruf von Python geschrieben und von diesem Modul gelesen werden kann. Folgende Typen werden unterstützt: Keine, ganze Zahlen, lange ganze Zahlen, Gleitkommazahlen, Strings, Unicode-Objekte, Tupel, Listen, Mengen, Wörterbücher und Codeobjekte, wo es zu verstehen, dass Tupel, Listen und Wörterbücher werden nur so lange unterstützt da die darin enthaltenen Werte sind selbst getragen wird; und rekursive Listen und Wörterbücher sollten nicht geschrieben werden (sie werden Endlosschleifen verursachen).

Nur auf der sicheren Seite zu sein, bevor die dict unmarshalling, sicherstellen, dass die Python-Version, die die dict entpackt die gleiche wie derjenige ist, den Marschall tat, da es keine Garantien für die Rückwärtskompatibilität sind.

Wenn die ‚shelve‘ Lösung färbt sich zu langsam oder knifflig zu sein, gibt es andere Möglichkeiten:

shelve wird wirklich langsam mit großen Datenmengen. Ich habe mit redis ganz erfolgreich und hat einen FreqDist Wrapper um ihn herum. Es ist sehr schnell, und kann gleichzeitig zugegriffen werden.

Sie können mit einem shelve speichern Ihre Daten auf CD, anstatt die gesamten Daten in den Speicher zu laden. So wird die Startzeit sehr schnell sein, aber der Kompromiss wird langsamer Zugriffszeit sein.

Shelve wird die dict Werte beizen, wird aber für jedes Element selbst die (un) Beize beim Start nicht für alle Gegenstände, aber nur bei Zugriffszeit tun.

Ein paar Dinge, die Importe beschleunigen helfen:

  1. Sie könnten versuchen, Python laufen die -OO-Flag verwenden, wenn Python ausgeführt wird. Dies wird einige Optimierungen tun, die Importzeit von Modulen reduzieren.
  2. Gibt es einen Grund, warum Sie das Wörterbuch nicht in kleinere Wörterbücher in separaten Modulen brechen könnte, die schneller geladen werden können?
  3. Als letzten Ausweg, können Sie die Berechnungen asynchron tun konnte, so dass sie nicht Ihr Programm verzögern, bis sie die Ergebnisse benötigt. Oder vielleicht sogar das Wörterbuch in einem separaten Prozess gestellt und übergeben Daten hin und her IPC verwenden, wenn Sie die Vorteile von Multi-Core-Architekturen nehmen.

Mit diesem wird gesagt, ich bin einverstanden, dass Sie sollten keine Verzögerung erleben in den Import-Module nach dem ersten Mal, wenn Sie es importieren. Hier sind ein paar andere allgemeine Gedanken:

  1. Importieren Sie das Modul innerhalb einer Funktion? Wenn ja dieses können führen zu Leistungsproblemen, da es zu prüfen hat und sehen, ob das Modul jedes Mal geladen wird die Import-Anweisung trifft.
  2. Ist Ihr Programm multi-threaded? Ich habe occassions gesehen, wo in einem Multi-Threaded-App auf Modul Import Code ausführen kann einige wonkiness und Instabilität der Anwendung (vor allem mit dem cgitb Modul) führen.
  3. Wenn dies eine globale Variable ist, bewusst sein, dass die globale Variable Lookup-mal als lokale Variable Lookup Zeiten erheblich länger sein kann. In diesem Fall können Sie eine deutliche Leistungssteigerung durch Bindung des Wörterbuch auf eine lokale Variable erreichen, wenn Sie es mehrmals im gleichen Kontext verwenden.

Mit diesem wird gesagt, es ist ein bisschen etwas schwierig Sie irgendeine spezifische Beratung ohne ein wenig mehr Kontext zu geben. Genauer gesagt, wenn importieren Sie es? Und was sind die Berechnungen?

  1. Faktor der rechenintensivste Teil in ein separates Modul. Dann wird zumindest auf Reload, werden Sie nicht warten müssen.

  2. Versuchen Sie, die Datenstruktur Dumping-Protokoll 2. Der Befehl würde versuchen cPickle.dump(FD, protocol=2). Vom docstring für cPickle.Pickler:

    Protocol 0 is the
    only protocol that can be written to a file opened in text
    mode and read back successfully.  When using a protocol higher
    than 0, make sure the file is opened in binary mode, both when
    pickling and unpickling. 
    

Ich werde durch dieses gleiche Problem ... ad acta legen, Datenbanken, etc ... sind auch alle für diese Art von Problem langsam. Sie werden den Hit einmal nehmen müssen, legen Sie sie in einen inmemory Schlüssel / val Geschäft wie Redis. Es wird nur dort leben in Speicher (Warn es eine gute Menge an Speicher aufbrauchen könnte, so dass Sie eine eigene Box möchten). Du wirst es nie zu laden haben und Sie erhalten nur für Schlüssel im Speicher suchen

r = Redis()
r.set(key, word)

word = r.get(key)

Aufbauend auf der verzögerten Berechnung Idee, warum nicht drehen Sie den dict in eine Klasse, die Vorräte (und Caches) Elemente wie nötig?

Sie können auch verwenden psyco Gesamtausführung zu beschleunigen ...

ODER Sie könnten nur eine Datenbank zum Speichern der Werte in Verwendung? Schauen Sie sich SQLObject, die es sehr einfach macht Sachen zu speichern, in einer Datenbank.

Es gibt eine andere ziemlich offensichtliche Lösung für dieses Problem. Wenn Code der ursprüngliche Umfang neu geladen wird, ist nach wie vor zur Verfügung.

So ... etwas zu tun, wie diese wird dieser Code stellen Sie sicher, nur einmal ausgeführt wird.

try:
    FD
except NameError:
    FD = FreqDist(word for word in brown.words())
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top