2

データベースからの高価な回答を保持している適切なpythonicプール/キャッシュオブジェクトで効率的にするにはどうすればよいですか?

私のモジュールには、次の回路図コードが含まれています。

import sqlite3

db = sqlite3.connect(config.DB) # application shared database
db.row_factory = sqlite3.Row

class Foo:

    def __init__(self, id):
        self.id = id

    @property
    def bar(self):
        if not hasattr(self, '_bar'):
            row = db.execute(
                'SELECT bar FROM bars WHERE id=?', (self.id, )).fetchone()
            self._bar = row['bar'] if row else None
        return self._bar

アプリケーションは、データベース内のFooいくつかの値にアクセスするために、その存続期間にわたってオブジェクトを作成しbarています。このFoo.barプロパティはコストのかかる操作であるため、処理が遅くなります。クラスのインスタンスFooはほとんど変更されていません。データベースに保存されているデータの読み取りプロキシにすぎません。

Foo同じインスタンスがid頻繁に作成および破棄されることに気づきました。オブジェクトが停止するたびに、の知識Foo.barが失われ、後でデータベースから再度フェッチする必要があります。

オブジェクト自体をプールするという2つの方法で対処する方法を考えました。

class DBObject:

    _pool = {}

    def __new__(cls, *params, **key_params):        
        key = cls.__name__ + str(params) + str(key_params)
        if not key in DBObject._pool:
            self = object.__new__(cls, *params, **key_params)
            DBObject._pool[key] = self
        self = DBObject._pool[key]
        return self

class Foo(DBObject):
    ...

またはそれらの状態:

class DBObject:

    _states = {}

    def __new__(cls, *params, **key_params):        
        self = object.__new__(cls, *params, **key_params)        
        key = cls.__name__ + str(params) + str(key_params)
        if not key in DBObject._states:
            DBObject._states[key] = {}            
        self.__dict__ = DBObject._states[key]
        return self

class Foo(DBObject):
    ...

より良い、より多くのpythonicソリューションはありますか?私は何かを監督しましたか?

PS:私はJava /C++のバックグラウンドを持つPythonの初心者です。

4

2 に答える 2

1

単純なメモ化デコレータを使用します。これが一般的なデコレータです。

import functools

def memoize(func):
    cache = {}
    sentinel = object()

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        key = (args, tuple(kwargs.items()))
        result = cache.get(key, sentinel)
        if result is not sentinel:
            return result
        result = func(*args, **kwargs)
        cache[key] = result
        return result       
    return wrapper

Fooクラスを飾るためにそれを使用することができます:

@memoize
class Foo:
...

memoizeメソッドにデコレータを適用barして、少しクリーンアップすることもできます。

@property
@memoize
def bar(self):
    row = db.execute('SELECT bar FROM bars where id=?', (self.id, )).fetchone()
    return row['bar'] if row else None

また、Python3.2の新functools.lru_cache機能として、多くの優れた機能(キャッシュのクリア、ヒット/ミス統計の追跡、オプションのサイズとタイプのチェック)があります。

于 2012-08-03T11:36:47.220 に答える
0

デコレータとして実装されたlrulfuキャッシュ

于 2012-08-03T11:30:46.727 に答える