我想保存时间并将对象标记为已修改,因此我编写了一个类并覆盖了它的__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 .so没有什么真正的改变
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%的时间,尽管成本仍然很高。
发布于 2012-11-02 21:33:17
不是一个完整的答案,但有一些建议:
self调用方法需要经过完整的方法解析顺序检查,那么运行时的开销将会更大。我不知道Python本身是否可以做MRO缓存。可能不是因为类型-存在-动态原则。因此,您应该能够通过将任何self.method(args)更改为classname.method(self, args)来减少一些开销。这就消除了调用的MRO开销。这适用于settattr()实现中的self.setModified()。在大多数地方,您已经通过引用object.setModified的功能转移到__setattr__本身。让我们知道每一个的时间是如何变化的。我会把实验分成两部分。
编辑:感谢你的计时数字。
开销可能看起来很大(看起来仍然是10倍)。然而,将其放在整体运行时的角度来看。换句话说:你的整个运行时中有多少时间会花在设置这些被跟踪的属性上,有多少时间会花在其他地方?
在单线程应用程序中使用Amdahl's Law is a simple rule来明确设置期望。举个例子:如果1/3的时间花在设置属性上,2/3的时间花在做其他事情上。那么,将属性设置减慢10倍只会减慢30%。花在属性上的时间百分比越小,我们需要关心的就越少。但如果你的百分比很高,这可能对你一点帮助都没有。
发布于 2012-11-02 23:22:03
在这里覆盖__setattr__似乎没有任何作用。您只有两个属性,modified和lastAccess。这意味着这是您唯一可以设置的属性,那么为什么要覆盖__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发布于 2017-06-08 05:39:00
这是一个老问题,但值得更新。
我在使用Python3.6的pydantic上遇到了同样的问题。
object.__setattr__(self, name, value)只是比通常在类上设置属性要慢一些。没有明显的办法绕过这一点。
如果性能很重要,那么惟一的选择就是在需要覆盖_setattr_的类中将对object.__setattr__(self, name, value)的调用保持在绝对最少。
https://stackoverflow.com/questions/13195510
复制相似问题