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

Performance 循环的并行版本不比串行版本快 我正在用C++编写一个程序来模拟特定的系统。对于每个时间步,执行的最大部分由单个循环占用。幸运的是,这是令人尴尬的并行,所以我决定使用Boost线程来并行化它(我在一台2核机器上运行)。我希望在加速接近2倍的串行版本,因为没有锁定。然而,我发现根本没有加速,performance,multithreading,parallel-processing,boost-thread,atomic-values,Performance,Multithreading,Parallel Processing,Boost Thread,Atomic Values,我实现了循环的并行版本,如下所示: 唤醒两个线程(它们被阻挡在屏障上) 然后,每个线程执行以下操作: 以原子方式获取并递增全局计数器 使用该索引检索粒子 对该粒子执行计算,并将结果存储在单独的数组中 等待工作完成 主线程等待作业完成 我使用这种方法是因为它应该提供良好的负载平衡(因为每次计算可能需要不同的时间)。我真的很好奇是什么可能导致这种减速。我总是读到原子变量速度很快,但现在我开始怀疑它们是否有性能成本 如果有人有什么想法或任何提示,我会非常感激。一个星期以来,我一直在对它进行猛烈

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

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

    • 以原子方式获取并递增全局计数器
    • 使用该索引检索粒子
    • 对该粒子执行计算,并将结果存储在单独的数组中
    • 等待工作完成
  • 主线程等待作业完成

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

如果有人有什么想法或任何提示,我会非常感激。一个星期以来,我一直在对它进行猛烈抨击,而分析并没有透露太多

编辑:问题已解决 我将详细说明我是如何解决这个问题的。我再次使用了gprof,但这次编译时没有使用优化标志(-O3)。立即,分析器显示我在函数中花费了难以置信的时间,该函数对每个粒子执行计算:比串行版本多得多

此函数是虚拟的,可通过多态方式访问。我改变了代码直接访问它,而不是通过vtable和瞧,并行版本产生了近2的加速!对串行版本的相同更改几乎没有影响

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

感谢所有的海报。你们都在一定程度上帮助了我,很难接受一个答案

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

计算有多重

  • 一般来说,原子计数器可能要花费数百个时钟周期,因此对其进行测试非常重要 请确保您不只是递增计数器
  • 还要试着看看每个线程做了多少工作——它们是否配合得很好(即在每个循环中,每个线程进行大约一半的粒子)
  • 尝试将作业细分为更大的块,然后是单个粒子(比如100个粒子等等)
  • 看看有多少工作是在线程之外完成的

老实说。。。看起来你所说的是一个bug。

评测并没有透露太多的信息

这还不清楚。我有在HP-UX上评测多线程应用程序的经验,他们的评测器显示每个函数运行的时间百分比。因此,如果函数中有一个或几个争用点,则应用程序在这些函数中花费的时间会增加。在我的例子中,
pthread\u mutex\u unlock()。当我修改代码时,它变得更快了

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


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

您说分析并没有透露太多,这(很遗憾)是典型的

下面是我要做的:

  • 回到单线程

  • 通过使用使单线程尽可能快。原因是探查器(大多数但不是全部)只擅长测量更改,而不是精确确定应该修复的内容

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


  • 你的语言很有启发性:

    等待xxx

    这可能是你的问题


    此外,再次添加到单个结果队列时速度会变慢—如果可能,您可能只在处理结束时将结果添加到单个队列中。主线程不应等待,请在每次更新后检查全局计数器。

    我将添加性能计数器,而不是分析,您将在最后记录这些计数器。您可能会将它们放入条件编译错误中,这样它们就不会添加到生产代码中。

    我可以建议您可能会发现OpenMP更容易实现这种并行性吗?因为您只想使循环并行,所以并不想显式地使用线程,而这正是OMP真正有效的地方


    无论如何值得一试。

    有趣的是,你有没有尝试过只计时的循环本身?是没有任何改善,还是只是令人失望的改善?您是否已签入任务管理器?您的应用程序是否确实创建了两个线程?应用程序内存密集吗?可能是内存瓶颈?您也可以尝试简单地拆分数组,让每个线程处理一半,看看是否会有任何区别。有一个令人失望的改进:加速比从0.9到1.1不等。任务管理器显示两个CPU都非常忙。线程本身不分配任何新内存。它们只对单个数组进行写操作,并对独立的位置进行写操作,而从不从同一个数组进行读取。当我把数组一分为二时,我得到了相似的性能