递归深度截止策略:并行快速排序
Posted
技术标签:
【中文标题】递归深度截止策略:并行快速排序【英文标题】:Recursion Depth Cut Off Strategy: Parallel QuickSort 【发布时间】:2013-03-25 19:00:43 【问题描述】:我实现了一个并行快速排序算法。为了避免过多并行线程的开销,我有一个截止策略,当向量大小小于特定阈值时,将并行算法转换为顺序算法。但是,现在我正在尝试根据递归深度设置截止策略。即我希望我的算法在达到某个递归深度时变为顺序。我使用了以下代码,但它不起作用。我不确定如何进行。有什么想法吗?
template <class T>
void ParallelSort::sortHelper(typename vector<T>::iterator start, typename vector<T>::iterator end, int level =0) //THIS IS THE QUICKSoRT INTERFACE
static int depth =0;
const int insertThreshold = 20;
const int threshold = 1000;
if(start<end)
if(end-start < insertThreshold) //thresholf for insert sort
insertSort<T>(start, end);
else if((end-start) >= insertThreshold && depth<threshold) //threshhold for non parallel quicksort
int part = partition<T>(start,end);
depth++;
sortHelper<T>(start, start + (part - 1), level+1);
depth--;
depth++;
sortHelper<T>(start + (part + 1), end, level+1);
depth--;
else
int part = partition<T>(start,end);
#pragma omp task
depth++;
sortHelper<T>(start, start + (part - 1), level+1);
depth--;
depth++;
sortHelper<T>(start + (part + 1), end, level+1);
depth--;
我尝试了静态变量depth
和非静态变量level
,但它们都不起作用。
注意:以上截图仅取决于depth
。包含level
以显示尝试的两种方法
【问题讨论】:
“它不起作用”是什么意思?它与预期的行为有何不同? 我的意思是它没有给我加速。但我已经想通了(答案如下)。无论如何,感谢您的关注。 假设单线程操作。那么在对sortHelper<T>
的调用中,depth
不等于level
?递归调用次数为level
。摆脱static depth
,您编写的静态变量在并行代码中几乎没有位置。
深度为 20 的递归二叉树有 100 万个条目。在您的情况下,您将拥有未定义的深度(因为 static depth
的值在您的代码中未定义,因为多个线程正在写入它而没有任何锁定保护)。
谁知道通过启动一群线程会在冷缓存影响上损失多少,以及当两个内核开始争夺包含它们的阵列部分的缓存行时,您会得到多少无用的缓存反弹正在发呆……
【参考方案1】:
static depth
从两个线程写入会使您的代码执行未指定的行为,因为未指定这些写入的作用。
碰巧的是,您正在传递level
,这是您的递归深度。在每个级别,您将线程数加倍——因此等于 6 的级别限制(例如)最多对应于 2^6 个线程。您的代码只有一半并行,因为partition
代码出现在主线程中,因此您可能会少于理论上同时运行的最大线程数。
template <class T>
void ParallelSort::sortHelper(typename vector<T>::iterator start, typename vector<T>::iterator end, int level =0) //THIS IS THE QUICKSoRT INTERFACE
const int insertThreshold = 20;
const int treeDepth = 6; // at most 2^6 = 64 tasks
if(start<end)
if(end-start < insertThreshold) //thresholf for insert sort
insertSort<T>(start, end);
else if(level>=treeDepth) // only 2^treeDepth threads, after which we run in sequence
int part = partition<T>(start,end);
sortHelper<T>(start, start + (part - 1), level+1);
sortHelper<T>(start + (part + 1), end, level+1);
else // launch two tasks, creating an exponential number of threads:
int part = partition<T>(start,end);
#pragma omp task
sortHelper<T>(start, start + (part - 1), level+1);
sortHelper<T>(start + (part + 1), end, level+1);
【讨论】:
【参考方案2】:好吧,我想通了。这是我的一个愚蠢的错误。
当堆栈大小大于某个阈值(而不是更小)时,算法应该回退到顺序代码。这样做可以解决问题,并加快速度。
【讨论】:
不,它不起作用。你观察到的是一个小故障。您不能以尝试使用它的方式跨线程使用静态变量 (depth
)。你得到的行为完全是虚假的。
你是对的。静态 depth
不是故障安全的。将level
与上述答案一起使用是可行的以上是关于递归深度截止策略:并行快速排序的主要内容,如果未能解决你的问题,请参考以下文章