【问题标题】: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&lt;T&gt; 的调用中,depth 不等于level?递归调用次数为level。摆脱static depth,您编写的静态变量在并行代码中几乎没有位置。
  • 深度为 20 的递归二叉树有 100 万个条目。在您的情况下,您将拥有未定义的深度(因为 static depth 的值在您的代码中未定义,因为多个线程正在写入它而没有任何锁定保护)。
  • 谁知道通过启动一群线程会在冷缓存影响上损失多少,以及当两个内核开始争夺包含它们的阵列部分的缓存行时,您会得到多少无用的缓存反弹正在发呆……

标签: c++ algorithm parallel-processing openmp quicksort


【解决方案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 与上述答案一起使用是可行的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 2021-04-09
    • 2022-10-05
    • 2013-10-08
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    相关资源
    最近更新 更多