提高heapq效率

时间:2015-10-03 00:06:41

标签: python performance heap

所以我发现自己利用heapq进行了一些计算。但是,对于我正在处理的问题,它运行缓慢,因为堆变得非常大。

我以为我可以选择加快速度。而不是创建一个巨大的堆,而不是堆成堆。但是,令我惊讶的是,“更高效”的代码明显变慢了。更有效的代码有更多的开销,但我真的认为它会赢得很多。在解决了这个问题后,我有两个功能可以进行相同的网络计算。 f1是“天真”(和更快)的版本。 f2是“改进的”(但速度较慢)版本。我在两者中做了一些随机数生成,但是我使用相同的种子,所以它实际上是一样的。

import random
import heapq
def f1():
    random.seed(1)
    Q=[0]
    while Q:
        value = heapq.heappop(Q)
        #print value
        if value<0.5:
            for counter in range(16):
                heapq.heappush(Q,value + 0.1 + (random.random()/1000))
    print value

def f2():
    random.seed(1)
    Q=[[0]]
    while Q:
        subQ = heapq.heappop(Q)
        value = heapq.heappop(subQ)
        #print value
        if subQ:
            heapq.heappush(Q,subQ)
        newQ = []
        if value<0.5:
            for counter in range(16):
                newQ.append(value + 0.1 + (random.random()/1000))
            heapq.heapify(newQ)
            heapq.heappush(Q,newQ)
    print value

为什么堆堆(f2)运行速度明显变慢?它应该调用heappush相同的次数,并且应用两次。但是堆的大小应该小得多,所以我预计它会跑得更快。

1 个答案:

答案 0 :(得分:0)

所以我只是没有足够的推动代码。这是一些修改过的代码。当subQ变得非常大时,我出现的好处就出现了。

def f1(m,n):
    random.seed(1)
    Q=[0]
    for counter in range(m):
        value = heapq.heappop(Q)
        #print value
        for newcounter in range(n):
            heapq.heappush(Q,random.random())
    print value #should be the same for both methods, so this is just a test

def f2(m,n):
    random.seed(1)
    Q=[[0]]
    for counter in range(1000000):
        subQ = heapq.heappop(Q)
        value = heapq.heappop(subQ)
        #print value
        if subQ:
            heapq.heappush(Q,subQ)
        newQ = []
        for newcounter in range(n):
            newQ.append(random.random())
        heapq.heapify(newQ)
        heapq.heappush(Q,newQ)
    print value #should be the same for both methods, so this is just a test

当我分析f1(1000000,10)f2(1000000,10)时,我的运行时间为10.7秒和14.8秒。相关细节如下:

F1:

  

ncalls tottime percall cumtime percall filename:lineno(function)

     

1000000 1.793 0.000 1.793 0.000 {_heapq.heappop}

     

10000000 3.856 0.000 3.856 0.000 {_heapq.heappush}

F2:

  

1000000 1.095 0.000 1.095 0.000 {_heapq.heapify}

     

2000000 2.628 0.000 2.628 0.000 {_heapq.heappop}

     

1999999 2.245 0.000 2.245 0.000 {_heapq.heappush}

     

10000000 1.114 0.000 1.114 0.000 {''追加''列表'对象}

因为额外的f2以及heappopheapify,网络append会失败。它在heappush上做得更好。

但是当我用更大的内部循环挑战它并运行f1(1000,100000)f2(1000,100000)时,我们得到了

F1:

  

1000 0.015 0.000 0.015 0.000 {_heapq.heappop}

     

100000000 28.730 0.000 28.730 0.000 {_heapq.heappush}

F2:

  

1000 19.952 0.020 19.952 0.020 {_heapq.heapify}

     

2000 0.011 0.000 0.011 0.000 {_heapq.heappop}

     

1999 0.006 0.000 0.006 0.000 {_heapq.heappush}

     

100000000 6.977 0.000 6.977 0.000 {''追加''列表'对象}

所以我们现在在heappush上做得更好,现在f2运行得更快(69秒对75秒)。

事实证明,我没有足够努力地推动我的代码。我需要把事情变得足够大,以致许多对heappush的调用变得比许多调用heapify要慢。