8

我有这个简单的代码可以帮助我测量类的__slots__性能(取自这里):

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 并且“从不”返回(等待几分钟 - 没有结果)。

到底是怎么回事?我应该__slots__在 PyPy 下使用吗?

如果我将不同的数字传递给,会发生以下情况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)
4

2 回答 2

12

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

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

于 2014-04-14T20:46:23.000 回答
8

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

于 2014-04-15T07:54:19.457 回答