La protection des données en mémoire en synchronisation avec un fichier pour longtemps en cours d'exécution de script Python

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

Question

J'ai un script Python (2.7) qui agit en tant que serveur et il sera donc fonctionner pendant de très longues périodes de temps. Ce script a un tas de valeurs de garder une trace de ce qui peut changer à tout moment en fonction des commentaires client.

Ce que je suis est idéalement après quelque chose qui peut garder une structure de données Python (avec des valeurs de types dict, list, unicode, int et float - JSON, essentiellement) en mémoire, me laissant le mettre à jour mais je veux (sauf le référencement l'une des instances de type référence plus d'une fois) tout en gardant ces données mises à jour dans un fichier lisible par l'homme, de sorte que même si la prise de courant a été tiré, le serveur pourrait juste commencer et continuer avec les mêmes données.

Je sais que je parle essentiellement sur une base de données, mais les données que je vais garder très simple et probablement moins de 1 Ko la plupart du temps, donc je suis à la recherche de la solution la plus simple possible qui peut me fournir avec l'intégrité des données décrites. Y at-il de bonnes bibliothèques Python (2.7) qui m'a laissé faire quelque chose comme ça?

Était-ce utile?

La solution

Je suis d'accord que vous n'avez pas besoin d'une base de données entièrement soufflé, il semble que tout ce que vous voulez est un fichier atomique écrit . Vous devez résoudre ce problème en deux parties, la sérialisation / désérialisation, et l'écriture atomique.

Pour la première section, json ou pickle sont probablement des formats approprié pour vous. JSON a l'avantage d'être lisible par l'homme. Il ne semble pas que ce le problème principal que vous êtes face à bien.

Une fois que vous avez sérialisé votre objet à une chaîne, utiliser la procédure suivante pour écrire un fichier sur le disque atomiquement, en supposant un seul auteur simultané (au moins sur Posix, voir ci-dessous):

import os, platform
backup_filename = "output.back.json"
filename = "output.json"

serialised_str = json.dumps(...)
with open(backup_filename, 'wb') as f:
     f.write(serialised_str)
if platform.system() == 'Windows':
     os.unlink(filename)
os.rename(backup_filename, filename)

Alors que os.rename est écrasera un fichier existant et est atomique sur POSIX, ce n'est malheureusement pas le cas sous Windows. Sous Windows, il y a la possibilité que os.unlink réussira, mais os.rename échouera, ce qui signifie que vous avez seulement backup_filename et pas filename. Si vous ciblez Windows, vous devrez considérer cette possibilité lorsque vous vérifiez l'existence de filename.

S'il y a une possibilité de plus d'un écrivain concurrent, vous devrez envisager une construction de synchronisation.

Autres conseils

Eh bien, puisque vous savez que nous parlons essentiellement sur une base de données, bien que très simple, vous ne sera probablement pas surpris que je vous suggère de jeter un oeil à la page Module sqlite3 .

Quel est le motif de l'exigence lisible par l'homme?

Je suggère à la recherche à SQLite pour une solution simple de base de données ou à cornichon pour un moyen simple d'objets serialise et les écrire sur le disque. Ni est particulièrement bien lisible.

D'autres options sont JSON ou XML que vous avez fait allusion à - utiliser les fonctions intégrées dans le module JSON pour sérialiser les objets puis écrire que sur le disque. Lorsque vous démarrez, vérifiez la présence de ce fichier et de charger les données si nécessaire.

De la docs :

>>> import json
>>> print json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)
{
    "4": 5,
    "6": 7
}

Puisque vous avez mentionné vos données est petite, je partirais avec une solution simple et utilise le cornichon Module , qui vous permet de vider un objet python dans une ligne très facilement .

Alors que vous venez de mettre en place un Discussion qui enregistre votre objet dans un fichier défini intervalles de temps.

Pas une solution « libraried », mais - si je comprends bien vos besoins -. Assez simple pour vous de ne pas vraiment besoin d'un

EDIT: vous avez mentionné que vous vouliez couvrir le cas où un problème se produit au cours de l'écriture elle-même, ce qui rend effectivement une transaction atomique. Dans ce cas, la façon traditionnelle de procéder est d'utiliser « récupération à base Log ». Il est en train d'écrire essentiellement un enregistrement dans un fichier journal en disant que « transaction d'écriture a commencé », puis l'écriture « transaction d'écriture comitted » lorsque vous avez terminé. Si un « commencé » n'a pas correspondant « commit », vous rollback.

Dans ce cas, je suis d'accord que vous pourriez être mieux avec une base de données simple comme SQLite. Il est peut-être une légère exagération, mais d'autre part, la mise en œuvre atomicité vous pourrait être réinventer la roue un peu (et je ne trouve pas de bibliothèques évidentes qui le font pour vous).

Si vous décidez d'aller dans le sens de rusés, ce sujet est abordé au chapitre de la synchronisation des processus du livre Systèmes d'exploitation de Silberschatz, sous la rubrique « transactions atomiques ».

Un très simple (mais peut-être pas « parfait transactionnellement ») alternative serait juste d'enregistrer un nouveau fichier à chaque fois, de sorte que si l'on corrompt vous avez une histoire. Vous pouvez même ajouter une somme de contrôle à chaque fichier pour déterminer automatiquement s'il est cassé.

Vous demandez comment mettre en œuvre une base de données qui fournit des garanties de ACID, mais vous ne fourni une bonne raison pour laquelle vous ne pouvez pas utiliser un impromptu. SQLite est parfait pour ce genre de chose et vous donne ces garanties.

Cependant, il y a KirbyBase . Je ne l'ai jamais utilisé et je ne pense pas que cela Garantit ACID, mais il a quelques-unes des caractéristiques que vous recherchez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top