简体   繁体   English

为什么我的Python脚本运行速度比HeapSort实现慢?

[英]Why does my Python script run slower than it should on my HeapSort implementation?

I've got as assignment to implement the heap sort algorithm into either Python or Java (or any other languages). 我已经完成将堆排序算法实现为Python或Java(或任何其他语言)的任务。 Since I'm not that really "fluent" in Python or Java I decided to do both. 由于我并不是真的能熟练使用Python或Java,因此我决定同时使用这两种方法。

But here I ran into a problem, the running time of the program is way too much hight than it "should" be. 但是在这里我遇到了一个问题,程序的运行时间比“应该”要高得多。 I mean by that, that the heap sort is supposed to run into a O(n * log n) and for current processor running on a clock rate of several GHz I didn't expect for that algorithm to run into over 2000secs for an array of size 320k 我的意思是,堆排序应该运行到O(n * log n),并且对于当前以几GHz时钟频率运行的处理器,我没想到该算法会在数组中运行超过2000秒大小320k

So for what I've done, I implemented the algorithm from the pseudo code of this sort in Python and in Java (I also tried the code in Julia from Rosetta Code to see if the running time was similar, why Julia ? Random pick) 因此,对于我所做的事情,我在Python和Java中从此类伪代码中实现了算法(我还尝试了Rosetta Code中的Julia中的代码,以查看运行时间是否相似,为什么选择Julia?随机选择)

So I checked the output for small input size problem, such as an array of size 10, 20 and 30. It appears that the array it correctly sorted in both languages/implementations. 因此,我检查了输出是否存在较小的输入大小问题,例如大小为10、20和30的数组。看来该数组在两种语言/实现中均正确排序。

Then I used the heapq library that implement this same algorithm to check once again if the running time was similar. 然后,我使用实现相同算法的heapq库再次检查运行时间是否相似。 It surprised me when it was actually the case... But after few tries I tried one last thing which is updating Python and then, the program using heapq ran much faster than the previous ones. 当确实如此时,这让我感到惊讶……但是经过几次尝试,我尝试了最后一件事,即更新Python,然后,使用heapq的程序比以前的程序运行得快得多。 Actually it was around 2k sec for the 320k array and now it around 1.5 sec or so. 实际上,320k阵列大约需要2k秒,而现在大约需要1.5秒。

I retried my algorithm and the problem was still there. 我重试了算法,问题仍然存在。

So here are the Heapsort class that I implemented: 所以这是我实现的Heapsort类:

class MaxHeap:
    heap = []

    def __init__(self, data=None):
        if data is not None:
            self.buildMaxHeap(data)

    @classmethod
    def toString(cls):
        return str(cls.heap)

    @classmethod
    def add(cls, elem):
        cls.heap.insert(len(cls.heap), elem)
        cls.buildMaxHeap(cls.heap)

    @classmethod
    def remove(cls, elem):
        try:
            cls.heap.pop(cls.heap.index(elem))
        except ValueError:
            print("The value you tried to remove is not in the heap")

    @classmethod
    def maxHeapify(cls, heap, i):
        left = 2 * i + 1
        right = 2 * i + 2
        largest = i
        n = len(heap)

        if left < n and heap[left] > heap[largest]:
            largest = left
        if right < n and heap[right] > heap[largest]:
            largest = right
        if largest != i:
            heap[i], heap[largest] = heap[largest], heap[i]
            cls.maxHeapify(heap, largest)

    @classmethod
    def buildMaxHeap(cls, heap):
        for i in range(len(heap) // 2, -1, -1):
            cls.maxHeapify(heap, i)
        cls.heap = heap

    @staticmethod
    def heapSort(table):
        heap = MaxHeap(table)

        output = []

        i = len(heap.heap) - 1
        while i >= 0:
            heap.heap[0], heap.heap[i] = heap.heap[i], heap.heap[0]
            output = [heap.heap[i]] + output
            heap.remove(heap.heap[i])
            heap.maxHeapify(heap.heap, 0)
            i -= 1
        return output

To log the runtime for each array size (10000 - 320000) I use this loop in the main function : 要记录每个数组大小(10000-320000)的运行时,我在main函数中使用以下循环:

     i = 10000
     while i <= 320000:
         tab = [0] * i
         j = 0
         while j < i:
             tab[j] = randint(0, i)
             j += 1
         start = time()
         MaxHeap.heapSort(tab)
         end = time()
         pprint.pprint("Size of the array " + str(i))
         pprint.pprint("Total execution time: " + str(end - start) + "s")
         i *= 2

If you need the rest of the code to see where the error could be, don't hesitate I'll provide it. 如果您需要其余代码来查看错误可能在哪里,请不要犹豫,我会提供它。 Just didn't want to share the whole file for no reasons. 只是不想无缘无故地共享整个文件。

As said earlier the running time I expected is from the worst case running time : O(n * log n) with modern architecture and a processor of 2.6GHz I would expect something around 1sec or even less (since the running time is asked in nanosecond I suppose that even 1 sec is still too long) 如前所述,我期望的运行时间来自最坏的运行时间:具有现代体系结构和2.6GHz处理器的O(n * log n),我希望大约1秒或更短的时间(因为运行时间要求以纳秒为单位)我想即使1秒仍然太长)

Here are the results : 结果如下:

Python (own) :                 Java (Own)

  Time        Size               Time       Size 
 593ms.       10k               243ms.      10k
 2344ms.      20k               600ms.      20k
 9558ms.      40k               1647ms.     40k
 38999ms.     80k               6666ms.     80k
 233811ms.    160k              62789ms.    160k
 1724926ms.   320k              473177ms.   320k

Python (heapq)                 Julia (Rosetta Code)
  Time        Size               Time        Size
 6ms.         10k               21ms.        10k
 14ms.        20k               21ms.        20k
 15ms.        40k               23ms.        40k
 34ms.        80k               28ms.        80k
 79ms.        160k              39ms.        160k
 168ms.       320k              60ms.        320k


And according to the formula the O(n * log n) give me :
40000       10k
86021       20k
184082      40k
392247      80k
832659      160k
1761648     320k

I think that these result could be used to determine how much time it should take depending on the machine (theoretically) 我认为这些结果可用于确定需要多少时间,具体取决于机器(理论上)

As you can see the high running time result comes from my algorithm, but I can't tell where in the code and that's why I'm asking here for help. 如您所见,运行时间长的结果来自我的算法,但是我无法确定代码在哪里,这就是为什么我在这里寻求帮助。 (Runs slow both in Java and Python) (Didn't try to use heap sort in java lib is there is one to see the difference with my implementation, my bad) (在Java和Python中运行速度都很慢)(没有尝试在java lib中使用堆排序是因为有一个可以看到与我的实现有区别的地方,我的错)

Thanks a lot. 非常感谢。

Edit : I forgot to add that I run this program on a MacBook Pro (last version MacOS, i7 2,6GHz. In case the problem could also comes from anything else than the code. 编辑:我忘了补充一点,我在MacBook Pro(最新版本的MacOS,i7 2,6GHz)上运行了该程序。以防万一问题也可能源于代码以外的其他问题。

Edit 2 : Here are the modifications I did on the algorithm, following the answer I received. 编辑2:这是我收到的答案之后,对算法所做的修改。 The program run approximately 200 times faster than previously, and so now it run in barely 2sec for the array of size 320k 该程序的运行速度比以前快了大约200倍,因此,对于大小为320k的数组,它现在仅需2秒即可运行

class MaxHeap:

    def __init__(self, data=None):
        self.heap = []
        self.size = 0

        if data is not None:
            self.size = len(data)
            self.buildMaxHeap(data)

    def toString(self):
        return str(self.heap)

    def add(self, elem):
        self.heap.insert(self.size, elem)
        self.size += 1
        self.buildMaxHeap(self.heap)

    def remove(self, elem):
        try:
            self.heap.pop(self.heap.index(elem))
        except ValueError:
            print("The value you tried to remove is not in the heap")

    def maxHeapify(self, heap, i):
        left = 2 * i + 1
        right = 2 * i + 2
        largest = i

        if left < self.size and heap[left] > heap[largest]:
            largest = left
        if right < self.size and heap[right] > heap[largest]:
            largest = right
        if largest != i:
            heap[i], heap[largest] = heap[largest], heap[i]
            self.maxHeapify(heap, largest)

    def buildMaxHeap(self, heap):
        for i in range(self.size // 2, -1, -1):
            self.maxHeapify(heap, i)
        self.heap = heap

    @staticmethod
    def heapSort(table):
        heap = MaxHeap(table)

        i = len(heap.heap) - 1
        while i >= 0:
            heap.heap[0], heap.heap[i] = heap.heap[i], heap.heap[0]
            heap.size -= 1
            heap.maxHeapify(heap.heap, 0)
            i -= 1
        return heap.heap

And it runs using the same main as given before 它使用与前面给出的相同的主函数运行

Its interesting that you posted the clock speed of your computer- you COULD calculate the actual number of steps your algorithm requires... but you would need to know an awful lot about the implementation. 有趣的是,您发布了计算机的时钟速度-您可以计算算法所需的实际步数...,但是您需要了解很多有关实现的知识。 For example, in python every time an object is created or goes out of scope, the interpreter updates counters on the underlying object, and frees the memory if those ref counts reach 0. Instead, you should look at the relative speed. 例如,在python中,每次创建对象或超出范围时,解释器都会更新基础对象上的计数器,并在这些引用计数达到0时释放内存。相反,您应该查看相对速度。

The third party examples you posted show the speed as less then doubling when the input array length doubles. 您发布的第三方示例显示,当输入数组长度加倍时,速度减慢然后加倍。 That doesn't seem right, does it? 这似乎不对,是吗? Turns out that for those examples the initial work of building the array probably dominates the time spent sorting the array! 事实证明,对于这些示例,构建数组的初始工作可能会占据对数组进行排序所花费的时间!

In your code, there is already one comment that calls out what I was going to say... 在您的代码中,已经有一条注释可以呼出我要说的话...

heap.remove(heap.heap[i]) This operation will go through your list (starting at index 0) looking for a value that matches, and then deletes it. heap.remove(heap.heap[i])此操作将遍历您的列表(从索引0开始)以查找匹配的值,然后将其删除。 This is already bad (if it works as intended, you are doing 320k comparisons on that line if your code worked as you expected!). 这已经很糟糕了(如果它按预期工作,那么如果您的代码按预期工作,那么您将在该行上进行320k比较!)。 But it gets worse- deleting an object from an array is not an in-place modification- every object after the deleted object has to be moved forward in the list. 但是,情况变得更糟-从数组中删除对象不是就地修改-删除的对象必须在列表中向前移动后的每个对象。 Finally, there is no guarantee that you are actually removing the last object there... duplicate values could exist! 最后,不能保证您实际上正在删除那里的最后一个对象……可能存在重复的值!

Here is a useful website that lists the complexity of various operations in python - https://wiki.python.org/moin/TimeComplexity . 这是一个有用的网站,列出了python中各种操作的复杂性-https: //wiki.python.org/moin/TimeComplexity In order to implement an algorithm as efficiently as possible, you need as many of your data structure operations to be O(1) as possible. 为了尽可能高效地实现算法,您需要将尽可能多的数据结构操作设为O(1)。 Here is an example... here is some original code, presumably with heap.heap being a list... 这是一个示例...这是一些原始代码,大概是用heap.heap作为列表...

        output = [heap.heap[i]] + output
        heap.remove(heap.heap[i])

doing

        output.append(heap.heap.pop())

Would avoid allocating a new list AND use a constant time operation to mutate the old one. 将避免分配新列表,并使用恒定时间操作来对旧列表进行变异。 (much better to just use the output backwards than use the O(n) time insert(0) method! you could use a dequeue object for output to get appendleft method if you really need the order) (比起使用O(n)时间insert(0)方法,只向后使用输出要好得多!如果您确实需要此命令,则可以使用出队对象进行输出以获得appendleft方法)

If you posted your whole code there are probably lots of other little things we could help with. 如果您发布了整个代码,则可能还有很多其他小事情我们可以帮助您。 Hopefully this helped! 希望这有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我的A *实施比洪水填充慢? - Why is my A* implementation slower than floodfill? 为什么我的Spark运行速度比纯Python慢​​? 性能比较 - Why does my Spark run slower than pure Python? Performance comparison Python中的基准测试:为什么我的代码在重复时运行得更慢? - Benchmarking in Python: Why does my code run slower with repetition? 为什么我的C ++文本文件解析脚本比Python脚本慢得多? - Why is my C++ text file parsing script so much slower than my Python script? 为什么我的Python脚本会永远运行? - Why does my Python script run forever? 为什么这个Python脚本在多个内核上的运行速度比单个内核慢4倍 - Why does this Python script run 4x slower on multiple cores than on a single core 为什么我的Python脚本比R脚本慢得多? - Why is my Python script so much slower than its R equivalent? Python特征值计算比我计算机上的MATLAB运行速度慢得多。 为什么? - Python eigenvalue computations run much slower than those of MATLAB on my computer. Why? 为什么这个算法在 Python 中的运行速度比 Java 慢 20 倍? - Why does this algorithm run 20 times slower in Python than Java? 为什么Python3在执行任务时比Python2慢得多? - Why is Python3 much slower than Python2 on my task?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM