web-dev-qa-db-fra.com

Conservez les variables persistantes en mémoire entre les exécutions du script Python

Existe-t-il un moyen de garder une variable de résultat en mémoire afin que je n’aie pas à la recalculer chaque fois que je lance le début de mon script? Je suis en train de faire une longue série (5 à 10 secondes) des opérations exactes sur un ensemble de données (que je lis sur le disque) chaque fois que j'exécute mon script ..__ Cela ne devrait pas poser trop de problème, car je suis assez doué pour utiliser l'éditeur interactif pour déboguer mon code entre les exécutions; Cependant, parfois, les capacités interactives ne suffisent pas.

Je sais que je pourrais écrire mes résultats dans un fichier sur disque, mais je voudrais éviter de le faire si possible. Cela devrait être une solution qui génère une variable la première fois que j'exécute le script et la garde en mémoire jusqu'à la fermeture du shell ou jusqu'à ce que je lui dise de manière explicite de disparaître. Quelque chose comme ça:

# 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)

Je pense que le module shelve pourrait être ce que je cherche ici, mais il me semble que pour ouvrir une variable shelve, je devrais spécifier un nom de fichier pour l'objet persistant, et je ' Je ne sais pas si c'est tout à fait ce que je recherche.

Avez-vous des conseils à faire pour que je puisse faire ce que je veux? Des idées alternatives?

43
machine yearning

Vous pouvez obtenir quelque chose comme ceci en utilisant la fonction globale reload pour réexécuter le code de votre script principal. Vous devrez écrire un script wrapper qui importera votre script principal, lui demandera la variable qu’il souhaite mettre en cache, en mettra une copie en cache dans la portée du module du script wrapper, puis à votre guise (lorsque vous appuierez sur ENTER sur stdin ou autre) ), il appelle reload(yourscriptmodule) mais cette fois-ci lui passe l'objet mis en cache de sorte que votre script puisse contourner le calcul coûteux. Voici un exemple rapide.

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

Pendant que wrapper.py est en cours d'exécution, vous pouvez éditer mainscript.py, ajouter un nouveau code à la fonction part2 et pouvoir exécuter votre nouveau code par rapport à part1Cache pré-calculé.

39
Peter Lyons

Si vous ne souhaitez conserver qu'un seul objet (ou graphique d'objet) lors de sessions ultérieures, le module shelve est probablement excessif. Il suffit de décaper l'objet qui vous intéresse. Faites le travail et enregistrez le cornichon si vous n'avez pas de fichier cornichon, ou chargez le fichier cornichon si vous en avez un.

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

Pour conserver les données en mémoire, le processus doit continuer à s'exécuter. La mémoire appartient au processus exécutant le script, PAS au shell. Le shell ne peut pas contenir de mémoire pour vous.

Donc, si vous voulez changer votre code et garder votre processus en marche, vous devrez recharger les modules quand ils seront modifiés. Si l'une des données en mémoire est une instance d'une classe qui change, vous devez trouver un moyen de la convertir en une instance de la nouvelle classe. C'est un peu le bordel. Peu de langues ont jamais été douées pour ce genre de correctif à chaud (on pense à Common LISP), et il y a beaucoup de chances que des problèmes se produisent.

5
Dietrich Epp

Le rack de Python est une solution de persistance pour les objets pickled (sérialisés) et est basé sur des fichiers. L'avantage est qu'il stocke les objets Python directement, ce qui signifie que l'API est assez simple.

Si vous voulez vraiment éviter le disque, la technologie que vous recherchez est une "base de données en mémoire". Plusieurs alternatives existent, voir cette question SO: base de données en mémoire en Python .

3
Ray Toal

Ceci est une solution dépendante de l'OS ...

$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

Cela vous permettra de modifier et de redéfinir les variables lors du premier processus sans rien copier ni recalculer. Ce devrait être la solution la plus efficace par rapport aux modules ou bases de données multitraitement, memcached, pickle, shelve.

C’est vraiment bien si vous voulez éditer et redéfinir second_process.py de manière itérative dans votre éditeur ou IDE jusqu’à ce que tout soit correct sans avoir à attendre le premier processus (par exemple initialiser un grand dict, etc.) le temps que vous faites un changement.

1
John

Vous pouvez exécuter un script persistant sur le serveur par l'intermédiaire du système d'exploitation qui charge/calcule, et même recharge/recalcie périodiquement les données SQL dans des structures de mémoire de quelque sorte, puis accédez aux données en mémoire de votre autre script via un socket.

0
Stephen

Vous pouvez le faire, mais vous devez utiliser un shell Python. En d'autres termes, le shell que vous utilisez pour démarrer les scripts Python doit être un processus Python. Ensuite, toutes les variables globales ou classes resteront en vigueur jusqu'à la fermeture du shell.

Examinez le module cmd qui facilite l’écriture d’un programme Shell. Vous pouvez même faire en sorte que toutes les commandes qui ne sont pas implémentées dans votre shell soient transmises au shell système pour être exécutées (sans fermer votre shell). Ensuite, vous devrez implémenter une sorte de commande, prun par exemple, qui exécute un script Python en utilisant le module runpy.

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

Vous devez utiliser le paramètre init_globals pour transmettre vos données spéciales à l'espace de noms du programme, idéalement un dict ou une instance de classe unique.

0
Michael Dillon