webentwicklung-frage-antwort-db.com.de

Behalten Sie persistente Variablen zwischen den Python-Skriptläufen im Speicher

Gibt es eine Möglichkeit, eine Ergebnisvariable im Speicher zu behalten, so dass ich sie nicht jedes Mal neu berechnen muss, wenn ich den Anfang meines Skripts ablaufe? Ich führe eine lange (5-10 Sekunden) Reihe der genauen Operationen aus ein Datensatz (den ich von der Festplatte lese) jedes Mal, wenn ich mein Skript ausführt .. Dies wäre kein allzu großes Problem, da ich ziemlich gut darin bin, den interaktiven Editor zu verwenden, um meinen Code zwischen den einzelnen Läufen zu debuggen. Manchmal schneiden die interaktiven Funktionen das aber einfach nicht ab.

Ich weiß, dass ich meine Ergebnisse in eine Datei auf der Festplatte schreiben könnte, aber ich möchte dies möglichst vermeiden. Dies sollte eine Lösung sein, die beim ersten Ausführen des Skripts eine Variable generiert und im Arbeitsspeicher aufbewahrt, bis die Shell selbst geschlossen wird oder ich sie explizit dazu auffordert, auszuflippen. Etwas wie das:

# Check if variable already created this session
in_mem = var_in_memory() # Returns pointer to var, or False if not in memory yet
if not in_mem:
    # Read data set from disk
    with open('mydata', 'r') as in_handle:
        mytext = in_handle.read()
    # Extract relevant results from data set
    mydata = parse_data(mytext)
    result = initial_operations(mydata)
    in_mem = store_persistent(result)

Ich habe eine Ahnung, dass das Modul shelve das ist, wonach ich hier suche, aber um eine Shelve-Variable zu öffnen, müsste ich einen Dateinamen für das persistente Objekt angeben. Ich bin nicht sicher, ob es genau das ist, wonach ich suche.

Irgendwelche Tipps, um ein Regal für das zu bekommen, was ich will? Irgendwelche alternativen Ideen?

43

So etwas erreichen Sie, wenn Sie die globale Funktion reload verwenden, um den Code Ihres Hauptskripts erneut auszuführen. Sie müssen ein Wrapper-Skript schreiben, das Ihr Hauptskript importiert, nach der Variable fragt, die zwischengespeichert werden soll, eine Kopie davon innerhalb des Modulbereichs des Wrapper-Skripts speichert und wann Sie möchten (wenn Sie die Eingabetaste bei stdin oder was auch immer drücken ), ruft es reload(yourscriptmodule) auf, aber dieses Mal übergibt es das zwischengespeicherte Objekt, sodass yourscript die teure Berechnung umgehen kann. Hier ist ein kurzes Beispiel.

wrapper.py  

import sys
import mainscript

part1Cache = None
if __== "__main__":
    while True:
        if not part1Cache:
            part1Cache = mainscript.part1()
        mainscript.part2(part1Cache)
        print "Press enter to re-run the script, CTRL-C to exit"
        sys.stdin.readline()
        reload(mainscript)

mainscript.py

def part1():
    print "part1 expensive computation running"
    return "This was expensive to compute"

def part2(value):
    print "part2 running with %s" % value

Während wrapper.py ausgeführt wird, können Sie mainscript.py bearbeiten, der part2-Funktion neuen Code hinzufügen und den neuen Code mit dem vorberechneten part1Cache ausführen.

39
Peter Lyons

Wenn Sie nur ein Objekt (oder ein Objektdiagramm) für zukünftige Sitzungen beibehalten möchten, ist das Regalmodul wahrscheinlich zu viel. Pickle einfach das Objekt, das dich interessiert. Machen Sie die Arbeit und speichern Sie die Pickle, wenn Sie keine Pickle-Datei haben, oder laden Sie die Pickle-Datei, wenn Sie eine haben.

import os
import cPickle as pickle

pickle_filepath = "/path/to/picklefile.pickle"

if not os.path.exists(pickle_filepath):
    # Read data set from disk
    with open('mydata', 'r') as in_handle:
        mytext = in_handle.read()
    # Extract relevant results from data set
    mydata = parse_data(mytext)
    result = initial_operations(mydata)
    with open(pickle_filepath, 'w') as pickle_handle:
        pickle.dump(result, pickle_handle)
else:
    with open(pickle_filepath) as pickle_handle:
        result = pickle.load(pickle_handle)
5
Matt Anderson

Damit die Daten im Speicher bleiben, muss der Prozess weiterlaufen. Der Arbeitsspeicher gehört zu dem Prozess, der das Skript ausführt, NICHT zur Shell. Die Shell kann kein Gedächtnis für Sie halten.

Wenn Sie also Ihren Code ändern und den Prozess weiterlaufen lassen möchten, müssen Sie die Module erneut laden, wenn sie geändert werden. Wenn es sich bei einem der Daten im Speicher um eine Instanz einer Klasse handelt, die geändert wird, müssen Sie einen Weg finden, diese in eine Instanz der neuen Klasse zu konvertieren. Es ist ein bisschen Chaos. Nicht viele Sprachen waren jemals für diese Art von Hot-Patching geeignet (Common LISP kommt mir in den Sinn), und es gibt viele Chancen, dass etwas schief geht.

5
Dietrich Epp

Python's Shelve ist eine Persistenzlösung für eingelegte (serialisierte) Objekte und ist dateibasiert. Der Vorteil ist, dass Python-Objekte direkt gespeichert werden, was bedeutet, dass die API ziemlich einfach ist.

Wenn Sie die Festplatte wirklich vermeiden möchten, ist die von Ihnen gesuchte Technologie eine "In-Memory-Datenbank". Es gibt mehrere Alternativen, siehe diese SO - Frage: In-Memory-Datenbank in Python .

3
Ray Toal

Dies ist eine OS-abhängige Lösung ...

$mkfifo inpipe

#/usr/bin/python3
#firstprocess.py
complicated_calculation()
while True:
 with open('inpipe') as f:
  try:
   print( exec (f.read()))
  except Exception as e: print(e)

$./first_process.py &
$cat second_process.py > inpipe

Auf diese Weise können Sie Variablen im ersten Prozess ändern und neu definieren, ohne etwas zu kopieren oder neu zu berechnen. Es sollte die effizienteste Lösung sein, verglichen mit Multiprocessing-, Memcached-, Pickle-, Shelving-Modulen oder Datenbanken.

Das ist wirklich schön, wenn Sie second_process.py iterativ in Ihrem Editor oder IDE so lange bearbeiten und neu definieren möchten, bis Sie es richtig haben, ohne auf den ersten Prozess (z. B. Initialisieren eines großen Diktats usw.) warten zu müssen Mal, wenn Sie eine Änderung vornehmen.

1
John

Sie können ein persistentes Skript auf dem Server über das Betriebssystem ausführen, das die SQL-Daten lädt/berechnet und sogar periodisch in Speicherstrukturen einer bestimmten Art neu lädt/neu berechnet und dann die In-Memory-Daten Ihres anderen Skripts über einen Socket abruft.

0
Stephen

Sie können dies tun, aber Sie müssen eine Python-Shell verwenden. Die Shell, die Sie zum Starten von Python-Skripts verwenden, muss also ein Python-Prozess sein. Dann bleiben alle globalen Variablen oder Klassen aktiv, bis Sie die Shell schließen.

Schauen Sie sich das Modul cmd an, das das Schreiben eines Shell-Programms erleichtert. Sie können sogar so einrichten, dass Befehle, die nicht in Ihrer Shell implementiert sind, zur Ausführung an die System-Shell übergeben werden (ohne Ihre Shell zu schließen). Dann müssten Sie einen Befehl implementieren, beispielsweise prun, der ein Python-Skript mithilfe des runpy-Moduls ausführt.

http://docs.python.org/library/runpy.html

Sie müssen den Parameter init_globals verwenden, um Ihre speziellen Daten an den Namespace des Programms zu übergeben, im Idealfall ein Diktat oder eine einzelne Klasseninstanz.

0
Michael Dillon