为什么使用__slots__会减慢此代码的速度?

时间:2017-07-27 06:02:59

标签: python performance class time slots

我在Usage of __slots__?中读到在Python中使用@Override public void onBackPressed() // Declare in the activity showing the alarm screen { // code here what should be done at back button press super.onBackPressed(); // This line handles the default action of back button } 实际上可以节省时间。但是,当我试图找到使用__slots__所花费的时间时,结果却相反。

datetime

...给出了输出:import datetime as t class A(): def __init__(self,x,y): self.x = x self.y = y t1 = t.datetime.now() a = A(1,2) t2 = t.datetime.now() print(t2-t1) 并使用插槽:

0:00:00.000011

...给出了输出:import datetime as t class A(): __slots__ = 'x','y' def __init__(self,x,y): self.x = x self.y = y t1 = t.datetime.now() a = A(1,2) t2 = t.datetime.now() print(t2-t1)

使用插槽实际上需要更长时间。为什么我们需要使用0:00:00.000021呢?

2 个答案:

答案 0 :(得分:5)

__slots__可以节省时间(取决于Python版本),但这通常不是您使用它的原因。真正节省的是记忆。您可以将属性直接存储在支持该对象的C结构中,而不是每个实例的相当大的__dict__,并且该类本身存储查找表映射的单个副本,从名称到每个属性的结构偏移。即使在具有密钥共享序列的现代Py3 x64上,对于密钥共享__dict__仍然是96字节,其中类具有单个实例属性,在对象结构本身的56个字节之上。

通过使用__slots__,您可以消除指向__dict____weakref__属性的16个字节,并完全消除__dict__

比较Py 3.5:

>>> class Foo:
...    def __init__(self, x): self.x = x
...
>>> sys.getsizeof(Foo(1)) + sys.getsizeof(Foo(1).__dict__)
152
>>> class Foo:
...    __slots__ = 'x',
...    def __init__(self, x): self.x = x
...
>>> sys.getsizeof(Foo(1))  # With __slots__, doesn't have __dict__ at all
48

每个实例节省超过100个字节;在Py2(没有密钥共享词典)上节省的费用更高。

因此__slots__通常不会更快(通常非常相似),但如果您正在制作数百万个实例,则每个实例保存100多个B可能会帮助您将代码保存在RAM中等等,而不是耗尽内存并将一半数据分页交换。

正如其他答案所指出的那样,您实际上从未真正访问过您的属性,因此您根本没有对插槽访问进行基准测试,这就是您没有看到任何差异的原因。使用ipython3 %%timeit魔法,我发现重复加载给定实例的x属性的时间大约快15%(__slots__为33.5 ns而39.2 ns没有),但这只在微基准测试中显而易见;它在实际代码中很少发生(实际工作不仅仅是属性查找)。在重要的情况下,将内存使用量减少2-3倍是一个更大的收益。

答案 1 :(得分:4)

  1. 您引用的文章说使用插槽提供更快 属性访问 - 您测试了对象创建的时间,以及 从未访问过对象的属性。
  2. 测试单个操作在统计上没有意义 - 测量100000次操作的时间。