代码之家  ›  专栏  ›  技术社区  ›  Il-Bhima

循环的并行版本不快于串行版本

  •  5
  • Il-Bhima  · 技术社区  · 15 年前

    我正在用C++编写一个程序来模拟特定的系统。对于每个timestep,执行的最大部分是由单个循环承担。幸运的是,这是令人尴尬的并行,所以我决定使用Boost线程来并行化它(我在一台2核机器上运行)。因为没有锁定,所以我希望它的加速速度接近串行版本的2倍。但是我发现根本没有加速。

    我实现了循环的并行版本,如下所示:

    • 唤醒两个线程(它们被阻挡在屏障上)。
    • 然后,每个线程执行以下操作:

      • 原子地获取和增加一个全局计数器。
      • 用那个索引检索粒子。
      • 对该粒子执行计算,将结果存储在单独的数组中
      • 等待作业完成屏障
    • 主线程等待作业完成屏障。

    我使用这种方法是因为它应该提供良好的负载平衡(因为每次计算可能需要不同的时间)。我真的很好奇是什么可能导致这种减速。我经常读到原子变量很快,但现在我开始怀疑它们是否有性能成本。

    如果有人知道该找什么或者有什么提示,我会非常感激的。我已经在上面敲了一个星期的头了,而分析并没有透露多少。

    编辑:问题解决! 我要详细说明我是如何解决这个问题的。我再次使用gprof,但这次编译时没有使用优化标志(-o3)。立刻,探查器显示我在对每个粒子执行计算的函数中花费了大量的时间:远远超过串行版本。

    这个函数是虚拟的,可以多态访问。我修改了代码直接访问它,而不是通过vtable和voila'的并行版本产生了近2个加速!同样的改变对串行版本没有什么影响。

    我不知道为什么会这样,如果有人知道,我会感兴趣的!

    感谢所有的海报。你们都在某种程度上有所帮助,接受一个答案是非常困难的。

    5 回复  |  直到 8 年前
        1
  •  2
  •   Salman Salman Artyom    8 年前

    对该粒子执行计算,将结果存储在单独的数组中

    计算有多重?

    • 一般来说,原子计数器可能要花费数百个时钟周期,因此 注意不要只递增计数器。
    • 还要试着看看每个线程做了多少工作-它们合作得好吗(例如 每个 每一个循环进行大约一半的粒子)。
    • 尝试将作业细分为更大的块,然后再细分为单个粒子(比如100个粒子等等)。
    • 看看有多少工作是在线程之外完成的。

    说真的?你说的好像是个虫子。

        2
  •  1
  •   Sergey Kurenkov    15 年前

    profiling has not revealed much

    这还不清楚。我有在HP-UX上分析多线程应用程序的经验,在那里他们的分析器显示每个函数运行的时间百分比。因此,如果您的函数中有一个或几个争用点,那么您的应用程序在这些函数中花费的时间会增加。就我而言,我在 pthread_mutex_unlock() . 当我修改代码时,它变得更快了。

    你能在这里发布一个线程和两个/四个线程的相同统计数据吗?以及每个测试中的计算次数。

    另外,我建议您(如果可能)在锁定互斥体的全局函数上设置断点。您可能会发现在您的算法中的某个地方,您偶然地锁定了一个全局互斥体。

        3
  •  1
  •   weismat    15 年前

    你的语言很有启发性:

    等待XXX

    这可能是你的问题。


    另外,当再次添加到单个结果队列时,速度会变慢-如果可能,您可以仅在处理结束时将结果添加到单个队列中。主线程不应等待,每次更新后请检查全局计数器。
    我不分析,而是添加性能计数器,您可以在最后记录这些计数器。您可以将它们放入条件编译错误中,这样就不会将它们添加到生产代码中。

        4
  •  0
  •   Community CDub    8 年前

    你说,分析并没有揭示太多,这(可悲)是典型的。

    我要做的是:

    1. 回到单线程。

    2. 使用 this profiling technique that works in any language and environment . 原因是,分析人员(大多数但不是全部)只擅长 测量变化 而不是 找出你应该解决的问题 .

    3. 然后返回到单线程单核,再次执行该过程。如果您发现一个线程或另一个线程在进程间通信上花费了大量时间,那么您需要重新处理它。

        5
  •  0
  •   Mr. Boy    15 年前

    我能建议您为这种并行性找到OpenMP更容易些吗?因为您只想使循环并行,所以不想显式地处理线程,这正是OMP真正有效的地方。

    无论如何值得一试。