ead*_*ead 7 python performance pypy
因为我想要实现的算法使用索引,1..n并且因为它非常容易将每个索引移动一个,所以我决定变得聪明并在每个列表的开头插入一个虚拟元素,因此我可以使用本文中的原始公式.
为了简洁起见,请考虑以下玩具示例:
def calc(N):
nums=[0]+range(1,N+1)
return sum(nums[1:]) #skip first element
Run Code Online (Sandbox Code Playgroud)
但是,我担心,我的结果是虚假的,因为我可以在某处意外访问第0个元素而不是意识到它.所以我变得更聪明,None而不是0作为第一个元素使用 - 每次算术操作都会导致运行时错误:
def calc_safe(N):
nums=[None]+range(1,N+1) #here we use "None"
return sum(nums[1:])
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,这个小小的变化导致了pypy的巨大性能损失(即使使用当前的5.8版本) - 代码变得慢了大约10倍!这是我机器上的时间:
pypy-5.8 cpython
calc(10**8) 0.5 sec 5.5 sec
calc_safe(10**8) 7.5 sec 5.5 sec
Run Code Online (Sandbox Code Playgroud)
作为一个侧节点:Cpython不关心,是否None使用.
所以我的问题是双重的:
None不是一个好主意,但为什么呢?None-approach 的安全性并保持性能?编辑:正如Armin所解释的那样,并非所有列表都相同,我们可以看到,通过以下方式使用了哪种策略:
import __pypy__
print __pypy__.strategy(nums)
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,它是IntegerListStrategy在第二种情况下ObjectListStrategy.如果我们使用大整数值(例如2**100)代替,则会发生同样的情况None.
PyPy 对于仅包含整数的列表有一个特殊情况——它像array.array. 如果里面有None,那么这个优化就不再起作用了。
这可能可以在 PyPy 内部修复,以允许 None 作为特殊情况......