C++ 并行执行比串行执行花费更多的时间?

C++ 并行执行比串行执行花费更多的时间?,c++,linux,tbb,C++,Linux,Tbb,我正在研究TBB中的任务实现,并运行了并行和串行计算斐波那契级数的代码 代码是: #include <iostream> #include <list> #include <tbb/task.h> #include <tbb/task_group.h> #include <stdlib.h> #include "tbb/compat/thread" #include "tbb/task_scheduler_init.h" using n

我正在研究TBB中的任务实现,并运行了并行和串行计算斐波那契级数的代码

代码是:

#include <iostream>
#include <list>
#include <tbb/task.h>
#include <tbb/task_group.h>
#include <stdlib.h>
#include "tbb/compat/thread"
#include "tbb/task_scheduler_init.h"
using namespace std;
using namespace tbb;

#define CutOff 2

long serialFib( long n ) {
if( n<2 )
return n;
else
return serialFib(n-1) + serialFib(n-2);
}


class FibTask: public task 
{
    public:
    const long n;
    long* const sum;

    FibTask( long n_, long* sum_ ) : n(n_), sum(sum_) {}

    task* execute() 
    {
        // cout<<"task id of thread is \t"<<this_thread::get_id()<<"FibTask(n)="<<n<<endl;  // Overrides virtual function task::execute    
                // cout<<"Task Stolen is"<<is_stolen_task()<<endl;
        if( n<CutOff ) 
        {
            *sum = serialFib(n);
        }
         else
         {
            long x, y;
            FibTask& a = *new( allocate_child() ) FibTask(n-1,&x);
            FibTask& b = *new( allocate_child() ) FibTask(n-2,&y);
            set_ref_count(3); // 3 = 2 children + 1 for wait // ref_countis used to keep track of the number of tasks spawned at                            the current level of the task graph
            spawn( b );
                      // cout<<"child id of thread is \t"<<this_thread::get_id()<<"calculating n ="<<n<<endl;
            spawn_and_wait_for_all( a ); //set tasks for execution and wait for them
            *sum = x+y;
        }
        return NULL;
    }
};


long parallelFib( long n ) 
{
    long sum;
    FibTask& a = *new(task::allocate_root()) FibTask(n,&sum);
    task::spawn_root_and_wait(a);
    return sum;
}


int main()
{     
     long i,j;
     cout<<fixed;

     cout<<"Fibonacci Series parallelly formed is "<<endl;
      tick_count t0=tick_count::now();
     for(i=0;i<50;i++)
     cout<<parallelFib(i)<<"\t";
    // cout<<"parallel execution of Fibonacci series for n=10 \t"<<parallelFib(i)<<endl;

     tick_count t1=tick_count::now();
     double t=(t1-t0).seconds();
     cout<<"Time Elapsed in Parallel Execution is  \t"<<t<<endl;
     cout<<"\n Fibonacci Series Serially formed is "<<endl;
     tick_count t3=tick_count::now();

     for(j=0;j<50;j++)
     cout<<serialFib(j)<<"\t";
     tick_count t4=tick_count::now();
     double t5=(t4-t3).seconds();
     cout<<"Time Elapsed in Serial  Execution is  \t"<<t5<<endl;
     return(0);
}
与串行执行相比,并行执行需要更多的时间。在这种情况下,并行执行需要2500秒,而串行执行大约需要167秒。 谁能解释一下原因吗?

开销

当您的实际任务是轻量级的时,协调/沟通占主导地位,您不会自动从并行执行中获益。这是一个相当普遍的问题

相反,试着串行地计算成本足够高的M个斐波那契数,然后并行地计算它们。您应该会看到一个增益。

开销

当您的实际任务是轻量级的时,协调/沟通占主导地位,您不会自动从并行执行中获益。这是一个相当普遍的问题


相反,试着串行地计算成本足够高的M个斐波那契数,然后并行地计算它们。你应该会看到收益。

如果没有更多信息,很难判断。您需要检查:您的计算机有多少个进程?是否有其他程序可能使用其他处理器? 如果您想真正并行运行并获得性能优势,那么操作系统必须能够分配至少2个空闲处理器。 此外,对于小任务,分配线程和收集其结果的开销
可能会超出并行执行的好处。

如果没有更多信息,很难判断。您需要检查:您的计算机有多少个进程?是否有其他程序可能使用其他处理器? 如果您想真正并行运行并获得性能优势,那么操作系统必须能够分配至少2个空闲处理器。 此外,对于小任务,分配线程和收集其结果的开销
可能会超过并行执行的好处。

我认为每个任务都会产生fibn-1+fibn-2的结果,这是正确的吗?从本质上说,你开始一个任务,然后开始另一个任务,依此类推,直到我们有大量的任务,我在尝试将它们全部计数时有点不知所措-我认为是n平方。每个这样的任务的结果被用来加上斐波那契数

首先,除了两个独立的递归计算之外,这里没有实际的并行执行。每个任务都依赖于它的子任务的结果,并且不能真正并行地做任何事情。另一方面,您正在执行大量的工作来设置每个任务。毫不奇怪,你没有看到任何好处


现在,如果你要计算斐波那契数1。。通过迭代,你开始,比方说,在你的系统中,每个处理器核心一个任务,和一个只使用一个循环的迭代解决方案相比,我相信这会显示出更好的改进

我认为每个任务都会产生fibn-1+fibn-2的结果,这是对的吗?从本质上说,你开始一个任务,然后开始另一个任务,依此类推,直到我们有大量的任务,我试着把它们全部数完时有些不知所措-我认为是n平方。每个这样的任务的结果被用来加上斐波那契数

首先,除了两个独立的递归计算之外,这里没有实际的并行执行。每个任务都依赖于它的子任务的结果,并且不能真正并行地做任何事情。另一方面,您正在执行大量的工作来设置每个任务。毫不奇怪,你没有看到任何好处


现在,如果你要计算斐波那契数1。。通过迭代,你开始,比方说,在你的系统中,每个处理器核心一个任务,和一个只使用一个循环的迭代解决方案相比,我相信这会显示出更好的改进

将截止值改为12,在Linux上使用-O优化编译/Windows上的O2,您应该会看到显著的加速

这个例子中有很多并行性。问题是,当截止时间=2时,有用的并行计算的各个单元都被调度开销所淹没。提高截止值应该可以解决问题

下面是分析。分析并行性有两个重要时刻:

工时-计算工时的总量。 span—关键路径的长度。 可用的并行度为工作/跨度

对于fibn,当n足够大时,功大致与fibn成正比[是的,它描述了它自己!]。span是调用树的深度-它大致与n成正比。所以平行度与fibn/n成正比。因此,即使对于n=10,也有大量可用的并行性来保持一台典型的2013年台式机的嗡嗡声

问题是TBB任务需要时间来创建、执行、同步和销毁。将切断值从2更改为12可使串行代码为ta 当工作规模太小,以至于调度开销会淹没它时,请停止工作。这是递归并行中的一种常见模式:并行递归,直到您完成了大量的工作,这些工作还不如串行完成。在其他类似OpenMP或Cilk Plus的并行框架中,也存在同样的问题:任务会有开销,尽管它们可能比TBB大或小。所有这些变化都是最佳阈值


试着改变截止时间。较低的值会使您获得更多的并行性,但会增加调度开销。值越高,并行性越低,但调度开销越小。在这两者之间,您可能会找到一系列能够提供良好加速的值。

将截止值更改为12,在Linux上使用-O优化编译/Windows上的O2,您应该会看到显著的加速

这个例子中有很多并行性。问题是,当截止时间=2时,有用的并行计算的各个单元都被调度开销所淹没。提高截止值应该可以解决问题

下面是分析。分析并行性有两个重要时刻:

工时-计算工时的总量。 span—关键路径的长度。 可用的并行度为工作/跨度

对于fibn,当n足够大时,功大致与fibn成正比[是的,它描述了它自己!]。span是调用树的深度-它大致与n成正比。所以平行度与fibn/n成正比。因此,即使对于n=10,也有大量可用的并行性来保持一台典型的2013年台式机的嗡嗡声

问题是TBB任务需要时间来创建、执行、同步和销毁。将截止时间从2更改为12允许串行代码在工作规模太小以至于调度开销会使其难以应付时接管。这是递归并行中的一种常见模式:并行递归,直到您完成了大量的工作,这些工作还不如串行完成。在其他类似OpenMP或Cilk Plus的并行框架中,也存在同样的问题:任务会有开销,尽管它们可能比TBB大或小。所有这些变化都是最佳阈值


试着改变截止时间。较低的值会使您获得更多的并行性,但会增加调度开销。值越高,并行性越低,但调度开销越小。在这两者之间,您可能会发现一系列具有良好加速性能的值。

这是一款四核处理器i3…是的,其他应用程序也在运行它的四核处理器i3…是的,其他应用程序也在运行