2

時間を節約し、オブジェクトを変更済みとしてマークしたいので、クラスを作成してその__setattr__関数をオーバーライドしました。

import time

class CacheObject(object):
    __slots__ = ('modified', 'lastAccess')
    def __init__(self):
        object.__setattr__(self,'modified',False)
        object.__setattr__(self,'lastAccess',time.time())

    def setModified(self):
        object.__setattr__(self,'modified',True)
        object.__setattr__(self,'lastAccess',time.time())

    def resetTime(self):
        object.__setattr__(self,'lastAccess',time.time())

    def __setattr__(self,name,value):
        if (not hasattr(self,name)) or object.__getattribute__(self,name)!=value: 
            object.__setattr__(self,name,value)
            self.setModified()

class example(CacheObject):
    __slots__ = ('abc',)
    def __init__(self,i):
        self.abc = i
        super(example,self).__init__()

t = time.time()
f = example(0)
for i in range(100000):
    f.abc = i

print(time.time()-t)

処理時間を計測したところ、2秒かかりました。オーバーライドされた関数をコメントアウトしたところ、処理時間は 0.1 秒でした。オーバーライドされた関数の方が遅いことはわかっていますが、ギャップが 20 倍近く大きすぎます。私は何か間違っているに違いないと思います。

cfiからの提案を取る

1.if条件を削除する

    def __setattr__(self,name,value):
#        if (not hasattr(self,name)) or object.__getattribute__(self,name)!=value: 
            object.__setattr__(self,name,value)
            self.setModified()

実行時間が 1.9 に短縮されました。少し改善されましたが、変更されていないオブジェクトを変更済みとしてマークすると、他のプロセスでより多くのコストがかかるため、オプションではありません。

2.self.funcをclassname.func(self)に変更

def __setattr__(self,name,value):
    if (not hasattr(self,name)) or object.__getattribute__(self,name)!=value: 
        object.__setattr__(self,name,value)
        CacheObject.setModified(self)

実行時間は 2.0 です。実際には何も変わっていません。

3) setmodified 関数の抽出

def __setattr__(self,name,value):
    if (not hasattr(self,name)) or object.__getattribute__(self,name)!=value: 
        object.__setattr__(self,name,value)
        object.__setattr__(self,'modified',True)
        object.__setattr__(self,'lastAccess',time.time())

実行時間が 1.2 になりました!!これは素晴らしいことです。コストはまだ高いですが、ほぼ 50% の時間を節約できます。

4

3 に答える 3

1

完全な答えではありませんが、いくつかの提案:

  1. 値の比較をなくすことはできますか? もちろん、それは実装の機能変更です。ただし、整数よりも複雑なオブジェクトが属性に格納されている場合、実行時のオーバーヘッドはさらに悪化します。

  2. 経由のメソッドへのすべての呼び出しは、self完全なメソッド解決順序チェックを通過する必要があります。Python が MRO キャッシュ自体を実行できるかどうかはわかりません。おそらく、types-being-dynamic の原則によるものではありません。self.method(args)したがって、 anyを に変更することで、オーバーヘッドをいくらか削減できるはずですclassname.method(self, args)。これにより、MRO オーバーヘッドが呼び出しから取り除かれます。これは、実装に適用さself.setModified()れますsettattr()。ほとんどの場所では、 への参照を使用してすでにこれを行っていますobject

  3. すべての関数呼び出しには時間がかかります。それらを削除して、たとえばsetModifiedの機能を__setattr__それ自体に移動することができます。

これらのそれぞれのタイミングがどのように変化するかを教えてください。私は実験を分割します。

編集:タイミング番号をありがとう。

オーバーヘッドは劇的に見えるかもしれません (それでも 10 倍のようです)。ただし、それを全体的なランタイムの観点から見てください。言い換えれば、これらの追跡された属性を設定するために全体の実行時間のどれくらいが費やされ、他の場所でどのくらいの時間が費やされるのでしょうか?

シングル スレッド アプリケーションでは、アムダールの法則は期待を正すための単純なルールです。例: 時間の 1/3 が属性の設定に費やされ、2/3 が他の作業に費やされる場合。次に、属性設定を 10 倍遅くしても、30% しか遅くなりません。属性に費やされる時間の割合が少ないほど、気にする必要が少なくなります。しかし、パーセンテージが高い場合、これはまったく役に立たないかもしれません...

于 2012-11-02T13:33:16.617 に答える
0

ここでのオーバーライド__setattr__には機能がないようです。modified と lastAccess の 2 つの属性しかありません。つまり、設定できる属性はこれだけなので、なぜオーバーライドするのでしょう__setattr__か? 属性を直接設定するだけです。

属性を設定するときに何かをしたい場合は、setter と getter を持つプロパティにします。それはより簡単で、はるかに魔法的ではありません。

class CacheObject(object):
    __slots__ = ('modified', 'lastAccess')

    def __init__(self):
        self.modified = False
        self.lastAccess = time.time()

    def setModified(self):
        self.modified = True
        self.lastAccess = time.time()

    def resetTime(self):
        self.lastAccess = time.time()

class example(CacheObject):
    __slots__ = ('_abc',)
    def __init__(self,i):
        self._abc = i
        super(example,self).__init__()

    @property
    def abc(self):
        self.resetTime()
        return self._abc


    @abc.setter
    def abc(self, value):
        self.setModified()
        self._abc = value
于 2012-11-02T15:22:02.537 に答える