簡體   English   中英

為什么我的代碼在pypy中比默認的python解釋器慢?

[英]Why is my code slower in pypy than the default python interpreter?

給定多個參與者n ,我需要找到H ,所有元組的列表,其中每個元組是聯盟的組合(參與者的角色,例如(1,2,3)是參與者1、2和3的聯盟。 ((1,2,3),(4,5),(6,))是遵守此規則的聯盟的組合-也是元組):每個玩家僅出現一次且僅出現一次(即僅出現在一個聯盟中) 。 PS聯盟的每種組合在代碼中稱為布局。

在開始時,我編寫了一個代碼段,在其中計算了所有聯盟的所有組合,並針對每個組合檢查了規則。 問題在於,對於5-6名玩家來說,聯盟的組合數量已經非常龐大,以至於我的電腦無法使用。 為了避免很大一部分計算(所有可能的組合,循環和ifs),我編寫了以下代碼(我進行了測試,它等效於之前的代碼片段):

from itertools  import combinations, combinations_with_replacement, product, permutations

players = range(1,n+1)
coalitions = [[coal for coal in list(combinations(players,length))] for length in players]

H = [tuple(coalitions[0]),(coalitions[-1][0],)]
combs = [comb for length in xrange(2,n) for comb in combinations_with_replacement(players,length) if sum(comb) == n]
perms = list(permutations(players))
layouts = set(frozenset(frozenset(perm[i:i+x]) for (i,x) in zip([0]+[sum(comb[:y]) for y in xrange(1,len(comb))],comb)) for comb in combs for perm in perms)
H.extend(tuple(tuple(tuple(coal) for coal in layout) for layout in layouts))
print H

解釋:說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.

我計算排列(燙發)。 最后,對於每個燙發和每個梳子,我計算出不同的可能布局。 set結果( layouts )以刪除重復項並添加到H。

H = [((1,),(2,),(3,)),((1,2,3),),((1,2),(3,)),((1,3),(2,)),((2,3),(1,))]

比較如下:

python script.py

  • 4:0.000520944595337秒
  • 5:0.0038321018219秒
  • 6:0.0408189296722秒
  • 7:0.431486845016秒
  • 8:6.05224680901秒
  • 9:76.4520540237秒

pypy script.py

  • 4:0.00342392921448秒
  • 5:0.0668039321899秒
  • 6:0.311077833176秒
  • 7:1.13124799728秒
  • 8:11.5973010063秒
  • 9:去phut

為什么pypy這么慢? 我應該改變什么?

首先,我想指出的是,您正在研究貝爾數 ,當您生成完所有子集后,這可能會減輕您的下一部分工作。 例如,很容易知道每個Bell集合的大小。 OEIS已經具有貝爾編號序列

我手工編寫了循環以生成Bell集。 這是我的代碼:

cache = {0: (), 1: ((set([1]),),)}

def bell(x):
    # Change these lines to alter memoization.
    if x in cache:
        return cache[x]
    previous = bell(x - 1)
    new = []
    for sets in previous:
        r = []
        for mark in range(len(sets)):
            l = [s | set([x]) if i == mark else s for i, s in enumerate(sets)]
            r.append(tuple(l))
        new.extend(r)
        new.append(sets + (set([x]),))
    cache[x] = tuple(new)
    return new

出於實際目的,我在此處包括一些備忘。 但是,通過注釋掉一些代碼並編寫其他代碼,您可以獲得以下未存儲的版本,該版本用於基准測試:

def bell(x):
    if x == 0:
        return ()
    if x == 1:
        return ((set([1]),),)
    previous = bell(x - 1)
    new = []
    for sets in previous:
        r = []
        for mark in range(len(sets)):
            l = [s | set([x]) if i == mark else s for i, s in enumerate(sets)]
            r.append(tuple(l))
        new.extend(r)
        new.append(sets + (set([x]),))
    cache[x] = tuple(new)
    return new

我的數字基於我從事大部分工作的Thinkpad的使用。 大多數較小的案例太快而無法可靠地進行測量(對於前幾個案例,每個試驗甚至都不到一毫秒),因此我的基准測試是測試bell(9)bell(11)

使用標准timeit模塊的CPython 2.7.11基准:

$ 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.

這是itertools.product上的Pypy問題。

https://bitbucket.org/pypy/pypy/issues/1677/itertoolsproduct-slower-than-nested-fors

請注意,我們的目標是確保itertools不會比普通Python慢​​很多,但我們並不真正在意使其與普通Python一樣快(或更快)。 只要它不會大大降低速度,就可以了。 (至少我不同意a)或b)更容易閱讀:-)

無需詳細研究代碼,它似乎大量使用了itertools組合,排列和乘積函數。 在常規CPython中,這些都是用編譯后的C代碼編寫的,目的是使它們快速運行。 Pypy沒有實現C代碼,因此這些功能變慢也就不足為奇了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM