【问题标题】:Using __slots__ under PyPy在 PyPy 下使用 __slots__
【发布时间】:2014-05-28 21:13:15
【问题描述】:

我有这个简单的代码可以帮助我测量带有__slots__ 的类的执行情况(取自here):

import timeit

def test_slots():
    class Obj(object):
        __slots__ = ('i', 'l')

        def __init__(self, i):
            self.i = i
            self.l = []

    for i in xrange(1000):
        Obj(i)

print timeit.Timer('test_slots()', 'from __main__ import test_slots').timeit(10000)

如果我通过 python2.7 运行它 - 我会在 6 秒左右得到一些东西 - 好吧,它确实比没有插槽时更快(而且内存效率也更高)。

但是,如果我在 PyPy 下运行代码(对于 Mac OS/X 使用 2.2.1 - 64 位),它开始使用 100% CPU 并且“从不”返回(等待几分钟 - 没有结果)。

发生了什么事?我应该在 PyPy 下使用__slots__ 吗?

如果我将不同的号码传递给timeit(),会发生以下情况:

timeit(10) - 0.067s
timeit(100) - 0.5s
timeit(1000) - 19.5s
timeit(10000) - ? (probably more than a Game of Thrones episode)

提前致谢。


请注意,如果我使用 namedtuples,则会观察到相同的行为:

import collections
import timeit

def test_namedtuples():
    Obj = collections.namedtuple('Obj', 'i l')

    for i in xrange(1000):
      Obj(i, [])

print timeit.Timer('test_namedtuples()', 'from __main__ import test_namedtuples').timeit(10000)

【问题讨论】:

  • 不管其他什么,在 CPython 下无限循环或花费 60 倍的程序是一个错误,应该与 PyPy 家伙一起提出。
  • 我实际上预计__slots__ 版本会更慢,因为这些类针对空间进行了优化,而不是针对属性检索进行了优化。
  • @alexce 据我了解,至少在 CPython 上使用很多意味着使用类似结构的机制而不是哈希表。这意味着更少的计算和更少的缓存抖动。为什么不应该更快?
  • @kwatford 在模块级别定义类确实有帮助 - pypytimeit(10000) 完成 ~0.45s,哇效果:)
  • @alecxe 我猜想创建类并没有完全被 jit 优化,你要求它做 10,000 次。每次运行都重新创建它也可能会丢弃它在每次运行中学到的优化。 PyPy 在预热时可能会很慢,所以尽量不要让它反复预热 :)

标签: python performance pypy slots


【解决方案1】:

直接回答标题中的问题:__slots__ 对 PyPy 的性能毫无意义(但不会损害)。

【讨论】:

  • 谢谢你,阿明。您能否添加或参考有关 PyPy 如何存储实例变量的任何信息?
  • @alecxe morepypy.blogspot.ca/2010/11/… 概述了方法。
【解决方案2】:

timeit 代码的大约 10,000 次迭代中,该类都是从头开始重新创建的。在 PyPy 中创建类可能不是一个经过优化的操作;更糟糕的是,这样做可能会丢弃 JIT 学习到的关于类的前一个化身的所有优化。在 JIT 预热之前,PyPy 往往很慢,因此执行需要它反复预热的操作会影响您的性能。

当然,这里的解决方案是简单地将类定义移到被基准测试的代码之外。

【讨论】:

  • 这很有趣,但有点令人失望。类创建是 CPython 下的轻量级操作,并且有一些编程风格肯定依赖于此。
  • @Marcin 我相信 PyPy 团队认为代码 sn-ps 比 CPython 慢是错误,所以请随意提交。特别是如果您知道在实际代码中快速创建短期类的一些用途。
  • 值得注意的是,即使在 CPython 下,创建一个新类也不是那么便宜。类占用数百字节,比典型对象多得多,并且位于(并且拥有)多个缓存中,因此分配和释放比普通对象慢得多。
  • 如果没有得到所有的 Haskelly monadic,你经常don't need them
猜你喜欢
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
  • 2021-05-07
  • 1970-01-01
  • 2013-01-17
  • 1970-01-01
相关资源
最近更新 更多