【发布时间】: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 在模块级别定义类确实有帮助 -
pypy和timeit(10000)完成~0.45s,哇效果:) -
@alecxe 我猜想创建类并没有完全被 jit 优化,你要求它做 10,000 次。每次运行都重新创建它也可能会丢弃它在每次运行中学到的优化。 PyPy 在预热时可能会很慢,所以尽量不要让它反复预热 :)
标签: python performance pypy slots