在PyPy下使用__slots__

ale*_*cxe 8 python performance pypy slots

我有这个简单的代码帮助我测量类的__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)
Run Code Online (Sandbox Code Playgroud)

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

但是,如果我在PyPy下运行代码(使用2.2.1 - 64位用于Mac OS/X),它开始使用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)
Run Code Online (Sandbox Code Playgroud)

提前致谢.


请注意,如果我使用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)
Run Code Online (Sandbox Code Playgroud)

kwa*_*ord 11

在10,000次左右的timeit代码迭代中,从头开始重新创建类.在PyPy中创建类可能不是一个优化良好的操作; 更糟糕的是,这样做可能会放弃JIT所学到的关于该类之前版本的所有优化.在JIT预热之前,PyPy往往很慢,所以做一些需要它反复预热的事情会让你的表现黯然失色.

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

  • 值得注意的是,即使在CPython下,创建一个新类并不便宜.类占用数百个字节,比典型对象多,并且(并且有)几个高速缓存,因此分配和释放比普通对象慢得多. (3认同)

Arm*_*igo 8

直接回答标题中的问题:__slots__对PyPy中的表现毫无意义(但没有伤害).

  • @alecxe http://morepypy.blogspot.ca/2010/11/efficiently-implementing-python-objects.html概述了这种方法. (4认同)