【问题标题】:Why does using __slots__ slow down this code?为什么使用 __slots__ 会减慢这段代码的速度?
【发布时间】:2018-01-02 16:39:33
【问题描述】:

我在Usage of __slots__? 中读到,在 Python 中使用 __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

使用插槽实际上需要更长的时间。那我们为什么要使用__slots__呢?

【问题讨论】:

  • 我注意到以这种方式手动使用datetime 不是定时代码的推荐方法。有a module meant for timing code snippets。并且(如答案中所述)您必须多次重复短操作以获得任何接近有意义的结果。

标签: python performance class time slots


【解决方案1】:

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

通过使用__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 倍是一个更大的收益。

【讨论】:

    【解决方案2】:
    1. 您引用的文章说使用插槽可以提供更快的速度 属性 access - 您测试了对象创建的时间,并且 从未访问过对象的属性。
    2. 测试单个操作在统计上没有意义 - 测量例如 100000 次操作的时间。

    【讨论】:

      猜你喜欢
      • 2018-11-30
      • 1970-01-01
      • 2012-01-02
      • 2019-01-03
      • 2021-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多