我想节省时间并将对象标记为已修改,因此我编写了一个类并覆盖其__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%的时间,但成本仍然很高。
答案 0 :(得分:1)
不是一个完整的答案,而是一些建议:
你能否消除价值比较?当然,这是您实现的功能更改。但如果在属性中存储比整数更复杂的对象,那么运行时的开销会更糟。
通过self
对方法的每次调用都需要经过完整的方法解析顺序检查。我不知道Python是否可以进行任何MRO缓存。可能不是因为类型 - 动态原理。因此,您应该可以通过将任何self.method(args)
更改为classname.method(self, args)
来减少一些开销。这消除了调用中的MRO开销。这适用于self.setModified()
实施中的settattr()
。在大多数地方,您已经参考了object
。
每个函数调用都需要时间。你可以消除它们,例如将setModified
的功能移至__setattr__
本身。
让我们知道每个时间的时间变化。我把实验分开了。
编辑:感谢时间数字。
开销可能看起来很激烈(似乎仍然是10倍)。然而,将其放入整体运行时的角度。换句话说:在设置这些跟踪属性以及在其他地方花费了多少时间时,您将花费多少总体运行时间?
在单线程应用程序Amdahl's Law is a simple rule中直接设置期望值。举例说明:如果1/3的时间用于设置属性,2/3用于做其他事情。然后将属性设置减慢10倍只会减慢30%。使用属性花费的时间百分比越小,我们就越不需要关心。但如果你的百分比很高,这可能对你没有帮助......
答案 1 :(得分:0)
覆盖__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
答案 2 :(得分:0)
旧问题,但值得更新。
我使用python 3.6与pydantic遇到了同样的问题。
object.__setattr__(self, name, value)
只比正常设置类的属性慢。没有明显的方法。
如果效果很重要,唯一的选择是在需要覆盖object.__setattr__(self, name, value)
的类中将_setattr_
的来电保持在绝对最小值。