多个pthread被多次调用;比串行代码慢

时间:2014-10-08 18:18:11

标签: c++ multithreading

我在2D离散域(LX,LY)上解决了4个eqns。这4个eqns需要解决1000个时间步长。 每个eqn在(i,j)位置需要参数a,b和c。 我在main()中动态创建了a_m,b_m和c_m,我将它们的地址传递给每个线程。

我创建了4个函数eq1,eq2,eq3,eq4。

我为每个eqn创建LX * LY个线程数。 每个线程id将在域LX,LY中重新表示唯一(i,j)。 因此,每个线程将仅在向量a_m,b_m,c_m中的特定数据位置(i,j)处工作。 然后,我在main()中按顺序调用4 eqn。 假设4个方程按顺序求解,参数a,b和c由每个方程在每个(i,j)处更新。

我的程序运行速度比串行计算慢。你能否提出一些加速的优化技巧。

我想创建4个线程,每个方程一个,并且每个线程解决LX * LY次都不会提高速度。

# define N LX*LY
struct thread_data
{
   int  thread_id, t;
   double *a, *b, *c ;
};

struct thread_data thread_data_array[N];


//Function declaration

void *eqn1(void *threadarg)
{
//implementation of eqn1
   pthread_exit(NULL);
   return 0;
}

void *eqn2(void *threadarg)
{
//implementation of eqn2

   pthread_exit(NULL);
   return 0;
}

void *eqn3(void *threadarg)
{
//implementation of eqn3
   pthread_barrier_wait (&barrier);
   pthread_exit(NULL);
   return 0;
}

void *eqn4(void *threadarg)
{
//implementation of eqn4
   pthread_exit(NULL);
   return 0;
}

//主

void * main(void *)
{
  pthread_t threadid[N];
//dynamically create a_m, b_m and c_m of size N each
  for(time=0; time<10000; time++)
    {

      for(i=0; i<N; i++)
        {
        //thread_data_array[i] is initialized
        // *a,*b,*c in thread_data_array[i] will save address of a_m,b_m,c_m created dynamically in main()
        pthread_create(threadid[i], eq1, (void *) &thread_data_array[i] );
        }

      for(i=0; i<N; i++)
        {
        //thread_data_array[i] is initialized
        // *a,*b,*c in thread_data_array[i] will save address of a_m,b_m,c_m created dynamically in main()
        pthread_create(threadid[i], eq2, (void *) &thread_data_array[i] );
        }

      for(i=0; i<N; i++)
        {
        //thread_data_array[i] is initialized
        // *a,*b,*c in thread_data_array[i] will save address of a_m,b_m,c_m created dynamically in main()
        pthread_create(threadid[i], eq3, (void *) &thread_data_array[i] );
        }

      for(i=0; i<N; i++)
        {
        //thread_data_array[i] is initialized
        // *a,*b,*c in thread_data_array[i] will save address of a_m,b_m,c_m created dynamically in main()
        pthread_create(threadid[i], eq4, (void *) &thread_data_array[i] );
        }

        for(j=0;j<N; j++) {
        pthread_join( threadid[j], NULL);
       }

    }

free(a_m); free(b_m); free(c_m);

}

2 个答案:

答案 0 :(得分:0)

首先,代码有一些错误。你的eq2,eq3,eq4循环将孤立之前创建的线程。我认为你的代码有不确定的行为。如果您修复了代码,那么您可以继续优化。

一个大问题是线程创建开销。你基本上创建和销毁线程1000次。如果与eq1,eq2 ...相关的代码很简单,则线程创建/销毁产生的开销很高。

如果您没有被迫使用pthreads,我会选择OpenMP。

如果要使用pthread,可能需要实现“线程池”

如果您选择OpenMP,您将执行以下操作:

  for(time=0; time<10000; time++)
  {
      #pragma omp parallel for
      for(i=0; i<N; i++)
      {
        eq1(&thread_data_array[i]);
        eq2(&thread_data_array[i]);
        eq3(&thread_data_array[i]);
        eq4(&thread_data_array[i]);
      }
   }

并且OpenMP运行时将根据您的计算机知道要启动的线程数。

答案 1 :(得分:0)

easy 可以使多线程应用程序运行得比单线程应用程序慢。

您甚至可以使用pthread功能使单线程应用程序运行得相当慢。例如,考虑一个由循环组成的函数,循环的主体递增全局计数器。您必须保护该增量以使此功能在多线程应用程序中可用。例如,将增量夹在互斥锁和解锁之间。这个线程安全的版本运行速度比基本版本慢得多,只有一个线程。添加另一个线程和繁荣!性能大幅下降。

虽然你不应该这样做,但上面显示了

  • 线程涉及一些开销。

  • 当争用率很高时,会产生巨大的开销和浪费。您希望代码在解锁和锁定之间执行某些操作。几乎所有关键做法都会破坏多线程的目的。

我之所以提到互斥锁是因为你省略了(没有显示)一堆代码。如果您在该省略的代码中进行了大量锁定和解锁,那么这可能是您问题的一部分。

使多线程应用程序执行比串行执行更糟糕的另一种方法是压倒您的计算机。根据经验,使用CPU不应该有超过M个活动线程,其中M是机器上有效CPU的数量。除非您在刀片服务器上运行代码,否则此M是一个很小的数字。如果您有多个M活动线程尝试使用CPU,则会产生很多争用。你的4 * N很可能比这个M更多。

你不能在线程之后产生线程并期望性能提高。这是降低性能的好方法。如果您希望使用粗粒度并行(例如,线程)并行运行大量计算,则最好使用线程池。线程池限制活动线程的数量。 POSIX线程不提供线程池功能。您必须自己动手或在互联网上找到符合您需求的一个。

另一种可以使多线程应用程序比串行执行更糟糕的方法是不加入已完成的线程。您正在使用代码创建许多无法连接的线程。即使它们已经完成,您仍然会遇到问题,因为那些已完成但未加入的线程表示会增加争用的资源。如果他们没有完成,你就会压倒你的机器。