拟合调度系统

时间:2012-09-27 11:20:39

标签: c++ multithreading queue multiprocessing openmp

我想用多个处理器并行化线性操作(将复杂的数学函数拟合到某个数据集)。

假设我的机器中有8个核心,我想要适合1000个数据集。我期望的是一些系统将1000个数据集作为队列,并将它们发送到8个核心进行处理,因此它首先将1000中的前8个作为FIFO。每个数据集的拟合时间通常与另一个不同,因此拟合的8个数据集中的一些可能比其他数据集更长。我想从系统中得到的是保存拟合数据集的结果,然后为每个完成的线程恢复从大队列(1000个数据集)中获取新数据集。这必须恢复,直到处理完整个1000个数据集。然后我可以继续我的计划。

这样的系统叫什么?在C ++上有那些模型吗?

我与OpenMP并行,并使用模板和多态等高级C ++技术。

感谢您的任何努力。

2 个答案:

答案 0 :(得分:1)

你基本上想要的是一个工作池(或一个线程池),它从一个队列中取出一个工作,处理它,然后继续另一个工作。 OpenMP提供了处理此类任务的不同方法,例如障碍(所有工人一直运行到某个点,只在满足某个要求时才进行)或减少,以便在工人设法计算各自的部分之后将值累积到全局变量中。

您的问题非常广泛,但我可以给您的另一个提示是查看MapReduce范例。在这个范例中,函数被映射到数据集上,并且结果被排序到桶中,这些桶使用另一个函数(可能再次使用相同的函数)来减少。在您的情况下,这意味着您的每个处理器/核心/节点都会在给定的数据集上映射给定的函数,并将结果存储桶发送到另一个负责组合它的节点。我想如果你想使用MapReduce和C ++而不使用特定的MapReduce框架,你必须研究MPI。当您在一个节点上运行该程序时,也许您可​​以使用OpenMP执行类似操作,因此在Web上搜索可能会有所帮助。

TL; DR 搜索工作人员线程池),障碍 MapReduce

答案 1 :(得分:1)

您可以将OpenMP parallel用于动态计划或OpenMP任务。两者都可以用于并行化每个迭代需要不同时间才能完成的情况。动态安排:

#pragma omp parallel
{
   Fitter fitter;
   fitter.init();
   #pragma omp for schedule(dynamic,1)
   for (int i = 0; i < numFits; i++)
      fitter.fit(..., &results[i]);
}

schedule(dynamic,1)使每个线程一次执行一次迭代,线程永远不会空闲,除非没有更多的迭代要处理。

使用任务:

#pragma omp parallel
{
   Fitter fitter;
   fitter.init();
   #pragma omp single
   for (int i = 0; i < numFits; i++)
   {
      #pragma omp task
      fitter.fit(..., &results[i]);
   }
   #pragma omp taskwait
   // ^^^ only necessary if more code before the end of the parallel region
}

其中一个线程运行for循环,生成1000个OpenMP任务。 OMP任务保留在队列中并由空闲线程处理。它的工作方式与动态for循环有些类似,但允许在代码构造中有更大的自由度(例如,使用可以并行化递归算法的任务)。 taskwait构造等待所有待处理任务完成。它隐含在并行区域的末尾,因此只有在并行区域结束之前跟随更多代码时才真正需要。

在这两种情况下,每次调用fit()都将在另一个线程中完成。您必须确保拟合一组参数不会影响其他组的拟合,例如fit()是一个线程安全的方法/函数。这两种情况还要求执行fit()的时间远远高于OpenMP结构的开销。

OpenMP任务需要OpenMP 3.0兼容的编译器。如果您在Windows上进行开发,这将排除MS VC ++的所有版本(即使是VS2012中的版本)。

如果您希望每个线程只有一个fitter实例初始化,那么您应该采取一些不同的方法,例如使fitter对象成为全局对象threadprivate

#include <omp.h>

Fitter fitter;
#pragma omp threadprivate(fitter)

...

int main()
{
   // Disable dynamic teams
   omp_set_dynamic(0);

   // Initialise all fitters once per thread
   #pragma omp parallel
   {
      fitter.init();
   }

   ...

   #pragma omp parallel
   {
      #pragma omp for schedule(dynamic,1)
      for (int i = 0; i < numFits; i++)
         fitter.fit(..., &results[i]);
   }

   ...

   return 0;
 }

此处fitterFitter类的全局实例。 omp threadprivate指令指示编译器将其放入线程局部存储中,例如,使它成为每线程全局变量。这些在不同的平行区域之间存在。您还可以在omp threadprivate局部变量上使用static。这些在不同的平行区域之间也存在(但仅在相同的功能中):

#include <omp.h>

int main()
{
   // Disable dynamic teams
   omp_set_dynamic(0);

   static Fitter fitter; // must be static
   #pragma omp threadprivate(fitter)

   // Initialise all fitters once per thread
   #pragma omp parallel
   {
      fitter.init();
   }

   ...

   #pragma omp parallel
   {
      #pragma omp for schedule(dynamic,1)
      for (int i = 0; i < numFits; i++)
         fitter.fit(..., &results[i]);
   }

   ...

   return 0;
 }

omp_set_dynamic(0)调用禁用动态团队,即每个并行区域将始终使用OMP_NUM_THREADS环境变量指定的线程执行。