11

Pythonでオブジェクトの永続性を実装する方法についてアドバイスを求めています。もっと正確に言うと、Pythonオブジェクトをファイルにリンクして、そのファイルの表現を開くPythonプロセスが同じ情報を共有し、どのプロセスもそのオブジェクトを変更でき、その変更がに伝播するようにしたいと思います。他のプロセス、およびオブジェクトを「保存」しているすべてのプロセスが閉じられた場合でも、ファイルは残り、別のプロセスで再度開くことができます。

私はPythonのディストリビューションでこれの3つの主要な候補を見つけました-anydbm、pickle、shelve(dbmは完璧に見えましたが、Unixのみであり、私はWindowsを使用しています)。ただし、それらにはすべて欠陥があります。

  • anydbmは文字列値の辞書のみを処理できます(すべてに文字列キーと文字列値を持つ辞書のリストを格納しようとしていますが、理想的には型制限のないモジュールを探します)
  • シェルフでは、変更が伝播する前にファイルを再度開く必要があります。たとえば、2つのプロセスAとBが同じファイル(シェルフされた空のリストを含む)をロードし、Aがリストにアイテムを追加してsync()を呼び出す場合、Bはファイルをリロードするまで、リストは空であると見なされます。
  • pickle(現在テスト実装に使用しているモジュール)には、shelveと同じ「リロード要件」があり、以前のデータを上書きしません。プロセスAが15個の空の文字列をファイルにダンプし、次に文字列'hello'をダンプする場合、プロセスBは、「hello」文字列を取得するためにファイルを16回ロードする必要があります。私は現在、書き込み操作の前にファイルの終わりまで繰り返し読み取りを行い(「書き込み前にスレートをきれいに拭く」)、すべての読み取り操作をファイルの終わりまで繰り返すことでこの問題に対処していますが、より良い方法。

私の理想的なモジュールは次のように動作します(「A >>>」はプロセスAによって実行されるコードを表し、「B >>>」コードはプロセスBによって実行されます)。

A>>> import imaginary_perfect_module as mod
B>>> import imaginary_perfect_module as mod
A>>> d = mod.load('a_file') 
B>>> d = mod.load('a_file')
A>>> d
{}
B>>> d
{}
A>>> d[1] = 'this string is one'
A>>> d['ones'] = 1   #anydbm would sulk here
A>>> d['ones'] = 11 
A>>> d['a dict'] = {'this dictionary' : 'is arbitrary', 42 : 'the answer'}
B>>> d['ones']   #shelve would raise a KeyError here, unless A had called d.sync() and B had reloaded d
11    #pickle (with different syntax) would have returned 1 here, and then 11 on next call
(etc. for B)

pickleを使用する独自のモジュールを作成し、上記の繰り返し読み取りを使用するようにダンプとロードの動作を編集することで、この動作を実現できましたが、この問題が発生したことがなく、修正されたとは信じられません。以前は、より才能のあるプログラマーによって。さらに、これらの繰り返しの読み取りは私には非効率に思えます(ただし、操作の複雑さに関する知識は限られており、これらの繰り返しの読み取りは、棚のような明らかに滑らかなモジュールの「舞台裏」で行われている可能性があります)。したがって、私は私のために問題を解決するいくつかのコードモジュールが欠けているに違いないと結論付けます。誰かが私を正しい方向に向けたり、実装についてアドバイスをくれたりしてくれたらありがたいです。

4

3 に答える 3

11

ZODB代わりに(Zope Object Database)を使用してください。ZEOに支えられて、それはあなたの要件を満たします:

  • Pythonオブジェクトの透過的な永続性

    ZODBはその下でピクルスを使用するため、ピクルス可能なものはすべてZODBオブジェクトストアに格納できます。

  • 完全なACID互換トランザクションサポート(セーブポイントを含む)

    つまり、1つのプロセスからの変更は、準備が整ったときに他のすべてのプロセスに伝播し、各プロセスはトランザクション全体でデータを一貫して表示します。

ZODBは10年以上前から存在しているので、この問題はすでに解決されていると思います。:-)

ZODBでは、ストレージをプラグインできます。最も一般的な形式はFileStorageです。これは、大きなオブジェクト用のオプションのBLOBストレージを備えた1つのData.fsにすべてを格納します。

一部のZODBストレージは、機能を追加するために他のストレージのラッパーです。たとえば、DemoStorageはメモリ内の変更を保持して、単体テストとデモンストレーションのセットアップを容易にします(再起動すると、再びクリーンな状態になります)。BeforeStorageは、特定の時点より前のトランザクションからのみデータを返す、時間枠を提供します。後者は、失われたデータを回復するのに役立ちました。

ZEOは、クライアントサーバーアーキテクチャを導入するプラグインです。ZEOを使用すると、一度に複数のプロセスから特定のストレージにアクセスできます。必要なのが1つのプロセスからのマルチスレッドアクセスのみである場合、このレイヤーは必要ありません。

同じことは、PostgreSQL、MySQL、OracleなどのリレーショナルデータベースにZODBデータを格納するRelStorageでも実現できます。

于 2012-05-31T09:54:29.483 に答える
2

初心者の場合、次のようにシェルフデータベースをZODBデータベースに移植できます。

#!/usr/bin/env python
import shelve
import ZODB, ZODB.FileStorage
import transaction
from optparse import OptionParser
import os
import sys
import re

reload(sys)
sys.setdefaultencoding("utf-8")

parser = OptionParser()

parser.add_option("-o", "--output", dest = "out_file", default = False, help ="original shelve database filename")
parser.add_option("-i", "--input", dest = "in_file", default = False, help ="new zodb database filename")

parser.set_defaults()
options, args = parser.parse_args()

if options.in_file == False or options.out_file == False :
    print "Need input and output database filenames"
    exit(1)

db = shelve.open(options.in_file, writeback=True)
zstorage = ZODB.FileStorage.FileStorage(options.out_file)
zdb = ZODB.DB(zstorage)
zconnection = zdb.open()
newdb = zconnection.root()

for key, value in db.iteritems() :
    print "Copying key: " + str(key)
    newdb[key] = value

transaction.commit()
于 2014-05-15T04:39:50.180 に答える
0

TinyDBを使用することをお勧めします。はるかに優れており、簡単に使用できます。

https://tinydb.readthedocs.io/en/stable/

于 2020-10-27T22:08:03.553 に答える