代码之家  ›  专栏  ›  技术社区  ›  Nico Schertler

OpenMP按需嵌套并行

  •  1
  • Nico Schertler  · 技术社区  · 7 年前

    我有一个与OpenMP并行处理的作业列表:

    void processAllJobs()
    {
    #pragma omp parallel for
        for(int i = 0; i < n; ++i) 
            processJob(i);
    }
    

    所有作业都有一些连续的部分,如果单独调用,这些部分可以并行:

    void processJob(int i)
    {
        for(int iteration = 0; iteration < iterationCount; ++iteration)
        {
            doSomePreparation(i);
            std::vector<Subtask> subtasks = getSubtasks(i);
    #pragma omp parallel for
            for(int j = 0; j < substasks.size(); ++j)
                subtasks[j].Process();
            doSomePostProcessing(i)
        }
    }
    

    当我奔跑 processAllJobs() 为外部循环(每个作业)创建线程,内部循环(子任务)在线程中按顺序完成。这一切都很好,而且是有意的。

    有时,有非常大的工作需要花费很多时间来处理。足够长,这样外部循环中的所有其他线程都已经在最后一个线程之前完成,并且不做任何事情。是否有一种方法可以重新使用未使用的线程,以便在完成后立即将内部循环并行化?我想象一下,每当输入内部并行区域时,都会检查未使用线程的数量。

    我无法预测一份工作会持续多久。这可能不仅仅是一个长期的工作——也许有两三个。

    0 回复  |  直到 7 年前
        1
  •  3
  •   Michael Klemm    7 年前

    您对问题的描述听起来更像是OpenMP任务将是一个更好的选择。您的代码如下所示:

    void processAllJobs()
    {
    #pragma omp parallel master
        for(int i = 0; i < n; ++i) 
    #pragma omp task
            processJob(i);
    }
    

    然后该作业的处理过程如下所示:

    void processJob(int i)
    {
        for(int iteration = 0; iteration < iterationCount; ++iteration)
        {
            doSomePreparation(i);
            std::vector<Subtask> subtasks = getSubtasks(i);
    #pragma omp taskloop   // add grainsize() clause, if Process() is very short
            for(int j = 0; j < substasks.size(); ++j)
                subtasks[j].Process();
            doSomePostProcessing(i)
        }
    }
    

    这样,您就可以获得自然的负载平衡(假设您有足够的任务),而不必依赖嵌套的并行性。

    推荐文章