从多线程加速

时间:2014-07-04 12:26:38

标签: multithreading

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

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

有一个Win32和一个OpenMP版本,它们在执行时间方面几乎完全相同。我在一个4核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 个答案:

答案 0 :(得分:2)

  1. 我假设在bigtask()内没有完成同步(很明显,但我还是先检查一下)。
  2. 您可能遇到“脏缓存”问题:如果您操纵来自多个核心的彼此接近的数据(例如,相同的缓存行!),则每次操作都会将缓存行标记为脏(这意味着处理器需要向所有其他处理器发出信号,这反过来又涉及同步......)。
  3. 你创建了太多的线程(分配一个线程是一个很大的开销。所以为每个核心创建一个线程比每个线程创建5个线程更有效。)
  4. 我个人认为你有案例2(“Big Global Array”)。

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

    • 将结果写入本地数组,该数组在工作结束后由主线程合并到“Big Global Array”
    • 将全局数组拆分为几个较小的数组(并为每个线程提供其中一个数组)
    • 确保结构中的记录在Cache-Line边界上对齐(这有点像黑客,因为未来的处理器可能会更改缓存行边界) 您可能想尝试为每个线程创建数组的本地副本(至少对于结果)