游戏“生活”中发布和调试之间的加速比例奇怪

时间:2014-03-08 12:50:53

标签: c++ multithreading parallel-processing openmp

我用4边邻居写了经典游戏“生命”。当我在调试中运行它时,它会说:

  • 连续版本:4.2s
  • 并行版本:1.5s
哦,这很好。但如果我在发布中运行它,它会说:

  • 连续版本:0.46s
  • 并行版本: 1.23s

为什么呢?我在带有4个内核的计算机上运行它。我在并行部分运行4个线程。答案是对的。但有些是泄漏,我不知道那个地方。有人能帮助我吗?


我尝试在Visual Studio 2008和2012中运行它。结果是一样的。在项目设置中启用了OMP。

要重复我的问题,您可以找到已定义的常量PARALLEL并将其设置为1或0以相应地启用和禁用OMP。答案将在out.txtout.txt - 正确答案示例)中。输入必须在in.txt中(我的输入 - in.txt)。有一些俄语符号,你不需要理解它们,但in.txt中的第一个数字表示并行部分中运行的线程数(在示例中为4)。

主要部分放在StartSimulation功能中。如果您运行该程序,您将在控制台中看到一些带有运行时间的俄语文本。

程序代码足够大,所以我用文件托管添加它 - main.cpp(l2对我来说意味着“实验2”)

关于StartSimulation功能的一些评论。我将带有单元格的2D表面切割成小矩形。它由AdjustKernelsParameters函数完成。

2 个答案:

答案 0 :(得分:1)

我没有发现这个比例如此奇怪。有多个线程合作是一项复杂的业务,并且有开销。

需要序列化对共享内存的访问,这通常涉及某种形式的锁定机制以及线程之间的争用,它们必须等待锁被释放。 这些共享变量需要在处理器内核之间同步,这会导致显着的减速。此外,编译器需要将这些关键区域视为“序列点”。

当使用共享变量时,所有这些都减少了处理器硬件和编译器中每个线程的每线程优化的范围。

在这种情况下,似乎并行化的开销超过了单线程案例的优化可能性。

如果在需要访问共享变量之前每个线程有更多的工作要做,那么这些开销就不那么重要了。

答案 1 :(得分:1)

您正在使用guided循环计划。这是一个非常糟糕的选择,因为您正在处理一个常规问题,即如果将域简单地划分为相同大小的块,每个任务可以轻松完成与其他任务完全相同的工作量。

schedule(guided)替换为schedule(static)。同时使用livingCount减少总和而不是使用锁定增量:

#if PARALLEL == 1
#pragma omp parallel for schedule(static) num_threads(kernelsCount) \
                         reduction(+:livingCount)
#endif
for (int offsetI = 0; offsetI < n; offsetI += kernelPartSizeN)
{
  for (int offsetJ = 0; offsetJ < m; offsetJ += kernelPartSizeM)
  {
    int boundsN = min(kernelPartSizeN, n - offsetI), 
        boundsM = min(kernelPartSizeM, m - offsetJ);

    for (int kernelOffsetI = 0; kernelOffsetI < boundsN; ++kernelOffsetI)
    {
      for (int kernelOffsetJ = 0; kernelOffsetJ < boundsM; ++kernelOffsetJ)
      {
        if(BirthCell(offsetI + kernelOffsetI, offsetJ + kernelOffsetJ))
        {
          ++livingCount;
        }
      }
    }
  }
}