我使用Python多线程来实现Quicksort。 Quicksort是在函数中实现的。它是一个递归函数。 每个线程调用Quicksort对它拥有的数组进行排序。每个线程都有自己的数组,用于存储需要排序的数字。 如果阵列大小较小(<10,000)。它运行正常。 但是,如果数组大小较大,则显示“最大递归深度超过”。 所以,我使用setrecursionlimit()函数将递归深度重置为1500.但程序直接崩溃... 以下是快速排序代码。如果不在多线程环境中,它可以很好地工作。 似乎多线程是递归深度问题的原因。
def partition (array, p, r):
x = array[r]
i = (p-1)
j = p
while (1):
if array[j] <= x:
i = (i+1)
temp = array[j]
array[j] = array[i]
array[i] = temp
j+=1
if j == r:
break
temp = array[i+1]
array[i+1] = array[r]
array[r] = temp
return i+1
def quicksort (array, p, r):
if p < r:
q = partition (array, p, r)
quicksort (array, p, q-1)
quicksort (array, q+1, r)
答案 0 :(得分:6)
听起来你真正的问题是“为什么使用线程时递归深度更短”?我会尝试回答这个问题。
首先,背景。每个级别的递归都存储在称为堆栈的内存区域中。不幸的是,系统必须提前分配堆栈空间,并且事先并不知道程序可能需要多少堆栈空间。这就是太多递归导致“最大递归深度”错误的原因:你的程序耗尽了所有的堆栈空间。
每个线程都需要自己的堆栈来存储当前在该线程中执行的函数列表。在单线程程序中,系统可以为该一个线程提供大量内存给堆栈。在多线程程序中,系统必须更加保守,并且每个线程只提供一个小堆栈。否则,具有多个线程的程序可能会快速耗尽所有系统内存,只有堆栈空间(大部分不会被使用)。
所有这些都是由操作系统和/或C库完成的,而Python(更确切地说,CPython)运行在C库之上。 Python努力阻止您使用整个C堆栈,因为这会导致硬崩溃而不仅仅是异常。您可以告诉Python如何使用setrecursionlimit
函数执行操作,但这不会更改实际可用堆栈空间量。
在具有bash shell的unix-ish系统上,您可以使用ulimit -s
命令更改堆栈大小。在bash shell提示符下键入help ulimit
以获取更多信息。
答案 1 :(得分:1)
你为什么要编写自己的快速例程?这是家庭作业吗?
如果没有,我建议使用内置的排序机制;它们对绝大多数情况都很好,并且不会受到递归深度问题的影响。如果您正在查看非常大的数据集,我建议您查看scipy和numpy提供的各种容器和算法。
如果纯粹是为了实现例程的好奇心,正如Marcelo在评论中所说,我们需要看代码。
答案 2 :(得分:1)
您正在使用quicksort的递归实现。 您希望使用迭代实现快速排序。
递归在Python中是不可扩展的(至少在CPython中),因此对于较大的输入,它将失败。您可以增加递归限制,但这只会让您扩展到更大的范围,而不是让您的实现真正扩展。如果你有太多的递归,它的代价是允许段错误的可能性。这种方法对于多线程代码也有效(或者说确实不起作用),你只需要做更多,因为每个线程的递归限制会更低。总而言之,这是一个失败的主张:改为使用迭代。
您正在使用线程(或计划),这通常是一个不好的迹象。线程令人困惑,危险和困难。更重要的是,Python中的线程不会为您提供并行执行,如果这是您所期望的。使用线程进行快速排序实现,特别是在Python中,可能不太理想。 (如果你被要求这样做,你至少应该退后一步,理解它可能不是最好的方法。)
答案 3 :(得分:0)
你遇到的问题是一个递归函数使用内存,并且有大量的元素,因而大量的递归,你的内存不足。这解释了为什么提高递归限制会使程序崩溃 - 你要求的内存比你的要多。
如果你真的想为大量元素实现快速排序,你会想要特别使用quicksort阅读有关内存使用情况的维基百科上的this文章。否则,正如Nathan建议的那样,Python已经内置了sorted()
函数。除非这是家庭作业或好奇心,否则我强烈建议使用它。
答案 4 :(得分:0)
以下是QuickSort的迭代代码
import time
import random
stack = []
def partition(data,p,q):
global stack
pivot = p
pivotvalue = data[q]
for index in range(p,q+1):
if data[index] < pivotvalue:
temp = data[index]
data[index] = data[pivot]
data[pivot] = temp
pivot = pivot + 1
temp = data[q]
data[q] = data[pivot]
data[pivot] = temp
return pivot
def qSort(data,p,q):
global stack
push(stack,p,q)
while isEmpty(stack) == False:
q = pop(stack)
p = pop(stack)
pivot = partition(data,p,q)
if pivot-1 > p:
push(stack,p,pivot-1)
if pivot+1 < q:
push(stack,pivot+1,q)
def push(stack,p,q):
stack.append(p)
stack.append(q)
def pop(stack):
global top
if(len(stack)==0):
return -1
element = stack.pop()
return element
def isEmpty(stack):
return len(stack) == 0
if __name__ == '__main__':
start_time = time.time()
data = (range(1000000,0,-1))
random.shuffle(data)
#print data
qSort(data,0,len(data)-1)
#print data
print time.time() - start_time, "seconds"