多线程加速



我有一个高度并行化的问题。同一个函数需要解决数百个不同的问题。每个问题在单核上平均花费120毫秒(0.12秒)的时间,但也有很大的差异,一些极端和罕见的问题可能花费10倍的时间。每个问题都需要内存,但内存是提前分配的。这些问题不需要磁盘I/O,而且它们在运行时不会来回传递任何变量。但是,它们可以访问同一个全局结构体的不同部分(数组元素)。

我有c++代码,基于别人的代码,工作。(没有显示结构体的全局数组。)它运行20个问题(例如),然后返回。我认为20足以平衡4核的可变性。我看到执行时间已经从大约10开始逐渐变平了。

有一个Win32和一个OpenMP版本,它们在执行时间方面的行为几乎相同。我在四核Windows系统上运行这个程序。我在下面包含了一些OpenMP代码,因为它更短。(我更改了名称等,使其更通用,我可能犯了错误-它不会独立编译)

与单线程版本相比,速度提升在2.3倍左右趋于平缓。所以如果单线程需要230秒,那么多线程需要100秒。我很惊讶,加速并没有接近4,内核的数量。

我应该失望吗?

我能做些什么来接近我的理论期望吗?

int split_bigtask(Inputs  * inputs, Outputs * results)
{
  for (int k = 0; k < MAXNO; k++)
    results->solved[k].value = 0;
  int res;
  #pragma omp parallel shared(inputs, outputs)
  {
    #pragma omp for schedule(dynamic)
    for (int k = 0; k < inputs->no; k++)
    {
      res = bigtask(inputs->values[k], 
                    outputs->solved[k], 
                    omp_get_thread_num()
                   );
    }
  }
  return TRUE;
}
  1. 我假设在bigtask()内没有同步完成(很明显,但我仍然会先检查它)。
  2. 这是可能的,你遇到了一个"脏缓存"的问题:如果你操作的数据是彼此接近(例如相同的缓存线!)从多个核心,每个操作将标记缓存线为脏(这意味着处理器需要信号这到所有其他处理器,这又涉及到同步…)。
  3. 你创建了太多的线程(分配一个线程是相当大的开销)。因此,为每个核心创建一个线程比为每个核心创建5个线程要高效得多。

我个人认为你有情况2 ("Big Global Array")。

问题的解决方案(如果确实是情况2):

  • 将结果写入本地数组,该数组在工作结束后由主线程合并为"大全局数组"
  • 将全局数组拆分为几个较小的数组(并为每个线程分配其中一个数组)
  • 确保结构中的记录在cache - line边界上对齐(这有点hack,因为缓存线边界可能会在未来的处理器中改变)您可能想尝试为每个线程创建数组的本地副本(至少对于结果)

最新更新