用两条语句并行化 while 循环(弗洛伊德循环检测算法)

Posted

技术标签:

【中文标题】用两条语句并行化 while 循环(弗洛伊德循环检测算法)【英文标题】:Parallelizing while loop with two statements (Floyd cycle detection algorithm) 【发布时间】:2016-02-07 07:56:27 【问题描述】:

我将尝试并行化以下简单 while 使用 OpenMP 循环成两个线程 (我的第一次步行尝试使用这项技术)。我尝试同时使用sectionstasks。尽管我把它分成两个线程并产生了正确的结果,但 性能 慢得令人无法接受。

while ( tortoise != hare ) 
    tortoise = f ( tortoise );
    hare = f ( f ( hare ) );

注意:f 是函数对象的const &(即它有一个T operator()(const T &r)

operator()的实现如下(d函数对象的成员变量):

T operator() ( const T &r ) const 
    return ( ( r % d ) * 10 );

我的第一个想法是创建线程的开销。所以我在封闭函数的最开始创建了team(它本身只被调用一次,而上面的while-loop本身可以有很多迭代(它是Floyd cycle detection algorithm的一部分)。

我在这里省略了我所有的 #pragma omp ... 尝试,因为它们都导致性能不佳。

编辑:

根据 @templatetypedef 的回答,我尝试了 Brent 算法。因为我需要注入一些计算弗洛伊德的第二个和第三个while-loop (构建一个预循环和循环值的数字数组,如以及使用霍纳方案计算多项式) Brent 没有给我添加此代码的任何要点。因此我更喜欢弗洛伊德。完整代码见here。

【问题讨论】:

f 是如何实现的?考虑到每个线程基本上都会调用 f 然后做大量工作以与另一个线程同步,你真的认为多线程会加快速度吗? @templatetypedef 因为我认为这两个语句可以并行处理,所以我想在多核 CPU 上尝试一下。我已将T operator()(const T &r) 的实现添加到问题中。 【参考方案1】:

我认为这里的问题是您尝试并行化的代码不能很好地并行化。可以这样想:每个线程基本上需要执行十几个算术运算来推进其指针,但随后需要与另一个线程同步以确认值不相同并且不能进行任何部分进展直到两个线程都完成。简单地锁定或解锁互斥体的成本为about 17ns,这可能与评估其中一个乌龟或兔子步骤所需的时间有关。因此,每个线程最终可能完成的工作量与单个循环迭代所完成的工作量差不多——而且可能更多——所以我严重怀疑你是否会通过这种方式获得加速。

现在,可行的方法是使用像 Brent 的循环查找算法这样的算法,它比 Floyd 的算法进行的比较更少,而且通常收敛速度更快。这很可能会让您更快地找到周期。

【讨论】:

好的,所以我对开销的假设可能是正确的。我已经尝试过 Brent 算法,但是我在 Floyd's 第二和第三@987654323 中注入 一些额外代码时遇到了问题@。但如果 Brent 的并行化可能更有希望。我必须尝试理解该变体,或者性能增益是否如此巨大,甚至不是注入我的代码,而是事后进行。 - 我会等待更多的想法,否则我会接受你的回答。 阅读en.wikipedia.org/wiki/Analysis_of_parallel_algorithms 以了解为什么任何试图显着提高弗洛伊德算法的并行加速的尝试都注定要失败,即使是在理想的理论机器上也是如此。周期检测的工作和跨度都将与周期长度成正比,因此它们的商将为 O(1)。

以上是关于用两条语句并行化 while 循环(弗洛伊德循环检测算法)的主要内容,如果未能解决你的问题,请参考以下文章

R中的并行while循环

while语句(内有实操)

c++中for循环和switch语句哪个更高效

带有 pragma omp 并行的嵌套循环,混乱起来

非for循环的OpenMP并行化

在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环