为什么pypy中的代码比默认的python解释器慢?
给定多个玩家为什么pypy中的代码比默认的python解释器慢?,python,performance,pypy,Python,Performance,Pypy,给定多个玩家n,我需要找到H,所有元组的列表,其中每个元组是联盟的组合(玩家的组合,例如,(1,2,3)是玩家1,2和3的组合。((1,2,3),(4,5),(6),)是联盟的组合,也是元组)这尊重了这条规则:每个玩家只出现一次(也就是说,只出现在一个联盟中)。 另外,在代码中,每种联盟组合称为布局 开始时,我编写了一个代码段,其中我计算了所有联盟的所有组合,并为每个组合检查了规则。问题是,对于5-6名玩家来说,联盟组合的数量已经太大了,以至于我的电脑坏了。 为了避免大部分计算(所有可能的组合、
n
,我需要找到H
,所有元组的列表,其中每个元组是联盟的组合(玩家的组合,例如,(1,2,3)是玩家1,2和3的组合。((1,2,3),(4,5),(6),)是联盟的组合,也是元组)这尊重了这条规则:每个玩家只出现一次(也就是说,只出现在一个联盟中)。
另外,在代码中,每种联盟组合称为布局
开始时,我编写了一个代码段,其中我计算了所有联盟的所有组合,并为每个组合检查了规则。问题是,对于5-6名玩家来说,联盟组合的数量已经太大了,以至于我的电脑坏了。
为了避免大部分计算(所有可能的组合、循环和ifs),我编写了以下内容(我进行了测试,与前面的代码片段相当):
说明:假设n=3
首先,我创建所有可能的联盟:
coalitions = [[(1,),(2,),(3,)],[(1,2),(1,3),(2,3)],[(1,2,3)]]
然后我用明显的组合初始化H:每个玩家在他自己的联盟中,每个玩家在最大的联盟中
H = [((1,),(2,),(3,)),((1,2,3),)]
然后我计算所有可能的布局形式:
combs = [(1,2)] #(1,2) represents a layout in which there is
#one 1-player coalition and one 2-player coalition.
我计算排列(排列)。
最后,对于每个烫发和每个梳子,我计算出不同的可能布局。I设置
结果(布局
),以删除重复项并添加到H
H = [((1,),(2,),(3,)),((1,2,3),),((1,2),(3,)),((1,3),(2,)),((2,3),(1,))]
比较如下:
python script.py
- 4:0.00052094455337秒
- 5:0.0038321018219秒
- 6:0.0408189296722秒
- 7:0.431486845016秒
- 8:6.05224680901秒
- 9:76.4520540237秒
pypy脚本.py
- 4:0.00342392921448秒
- 5:0.066803932899秒
- 6:0.311077833176秒
- 7:1.13124799728秒
- 8:11.5973010063秒
- 9:Got phut
为什么pypy那么慢?我应该更改什么?这里有一个关于
itertools.product
的Pypy问题
请注意,我们的目标是确保itertools不会比
简单的Python,但我们并不真正关心如何使它完全一样快(或更快)
更快)作为普通Python。只要速度不太慢,就可以了。(在
至少我不同意你关于a)还是b)更容易阅读的观点:-)
在不详细研究代码的情况下,它似乎大量使用了
itertools
组合、排列和乘积函数。在常规的CPython中,这些都是用编译过的C代码编写的,目的是使它们变得更快。Pypy没有实现C代码,因此这些函数的速度较慢也就不足为奇了。这里是关于itertools.product
的Pypy问题
请注意,我们的目标是确保itertools不会比
简单的Python,但我们并不真正关心如何使它完全一样快(或更快)
更快)作为普通Python。只要速度不太慢,就可以了。(在
至少我不同意你关于a)还是b)更容易阅读的观点:-)
在不详细研究代码的情况下,它似乎大量使用了
itertools
组合、排列和乘积函数。在常规的CPython中,这些都是用编译过的C代码编写的,目的是使它们变得更快。Pypy没有实现C代码,因此这些函数的速度较慢也就不足为奇了。首先,我想指出的是,您正在研究,在生成所有子集之后,这可能会简化下一部分的工作。例如,很容易知道每个钟组有多大;OEIS已经有了
我手工编写循环以生成钟集;这是我的密码:
cache={0:(),1:((set([1]),),)}
def bell(x):
#更改这些行以更改备忘录。
如果x在缓存中:
返回缓存[x]
上一个=钟形(x-1)
新=[]
对于以前版本中的集合:
r=[]
对于范围内的标记(透镜(组)):
l=[s |集合([x]),如果i==在枚举(集合)中为i,s标记else s]
r、 附加(元组(l))
新.扩展(r)
new.append(set+(set([x]),)
缓存[x]=元组(新)
还新
为了实用,我在这里写了一些备忘录。但是,通过注释一些代码并编写一些其他代码,您可以获得以下未注释的版本,我将其用于基准测试:
def铃(x):
如果x==0:
返回()
如果x==1:
返回((集合([1]),),)
上一个=钟形(x-1)
新=[]
对于以前版本中的集合:
r=[]
对于范围内的标记(透镜(组)):
l=[s |集合([x]),如果i==在枚举(集合)中为i,s标记else s]
r、 附加(元组(l))
新.扩展(r)
new.append(set+(set([x]),)
缓存[x]=元组(新)
还新
我的数字是基于一个有几年历史的Thinkpad,我大部分的工作都是在它上面完成的。大多数较小的案例都太快了,无法可靠地进行测量(前几次试验中,每次试验都没有一毫秒),因此我的基准测试是通过bell(9)
测试bell(11)
CPython 2.7.11的基准测试,使用标准timeit
模块:
$ python -mtimeit -s 'from derp import bell' 'bell(9)'
10 loops, best of 3: 31.5 msec per loop
$ python -mtimeit -s 'from derp import bell' 'bell(10)'
10 loops, best of 3: 176 msec per loop
$ python -mtimeit -s 'from derp import bell' 'bell(11)'
10 loops, best of 3: 1.07 sec per loop
在PyPy 4.0.1上,也使用timeit
:
$ pypy -mtimeit -s 'from derp import bell' 'bell(9)'
100 loops, best of 3: 14.3 msec per loop
$ pypy -mtimeit -s 'from derp import bell' 'bell(10)'
10 loops, best of 3: 90.8 msec per loop
$ pypy -mtimeit -s 'from derp import bell' 'bell(11)'
10 loops, best of 3: 675 msec per loop
因此,我得出的结论是,itertools
在其预期习惯用法之外使用时速度不是很快。钟形数字在组合上很有趣,但它们不是从我能找到的任何简单的itertools
小部件组合中自然产生的
为了响应您最初的查询,即如何使其更快:只需打开代码即可。希望这有帮助
~C.首先,我想指出的是,您正在研究,在生成完所有t之后,这可能会简化下一部分的工作
$ pypy -mtimeit -s 'from derp import bell' 'bell(9)'
100 loops, best of 3: 14.3 msec per loop
$ pypy -mtimeit -s 'from derp import bell' 'bell(10)'
10 loops, best of 3: 90.8 msec per loop
$ pypy -mtimeit -s 'from derp import bell' 'bell(11)'
10 loops, best of 3: 675 msec per loop