【问题标题】:How to run a static parallel for loop without the main thread如何在没有主线程的情况下运行静态并行 for 循环
【发布时间】:2020-12-14 16:44:00
【问题描述】:

我想用多线程执行一个函数,而不使用主线程。所以这就是我想要的:

  # pragma omp parallel num_threads(9)
  {
     // do something
     # pragma omp for schedule(static,1)
     for(int i = 0; i < 10; i++)
        func(i); // random stuff
  }

所以我希望 func() 仅由 8 个线程执行,没有主线程。这有可能吗?

【问题讨论】:

  • 您确定要使用 1 的块大小进行调度吗?在大多数情况下,就缓存局部性而言,这是次优的。如果您没有充分的理由这样做,则应使用 static 而不指定块大小,以便使用最大块大小。对于非静态调度,可能希望块大小为 1,因为通常期望不同的循环迭代包含不同数量的工作。
  • @dreamcrash 对我们解决方案之间的差异有什么想法吗? ;)

标签: c multithreading parallel-processing openmp


【解决方案1】:

所以我希望 func() 仅由 8 个线程执行,没有 main 线。这有可能吗?

是的,你可以做到。但是,您必须实现

#pragma omp for schedule(static,1) 

因为,显式使用上述子句将使编译器自动在团队中的线程之间划分循环的迭代,包括该团队的 em> 线程,在您的代码示例中也是 main 线程。代码可能如下所示:

# pragma omp parallel num_threads(9) 
{
     // do something
      int thread_id = omp_get_thread_num();
      int total_threads = omp_get_num_threads();
      if(thread_id != 0) // all threads but the master thread
      {
        thread_id--; // shift all the ids
        total_threads = total_threads - 1;
        for(int i = thread_id ; i < 10; i += total_threads)
            func(i); // random stuff
      }
      #pragma omp barrier
} 

首先,我们确保除了 master 之外的所有线程都执行了要并行化的循环( if(thread_id != 0)),然后我们将循环的迭代划分为剩余线程( for(int i = thread_id ; i &lt; 10; i += total_threads)),最后我们确保所有线程在并行区域结束时相互等待( #pragma omp barrier) .

【讨论】:

    【解决方案2】:

    如果哪个线程不执行循环并不重要,另一种选择是将sections 与循环结合。这意味着嵌套并行性,应该非常小心,但它应该可以工作:

    #pragma omp parallel sections num_threads(2)
    {
        #pragma omp section
        { /* work for one thread */ }
          #pragma omp section
          {
              #pragma omp parallel for num_threads(8) schedule(static, 1)
              for (int i = 0; i < N; ++i) { /* ... */ }
          }
    }
    

    这里的主要问题是,这些部分中的一个很可能会比另一个花费更长的时间,这意味着在最坏的情况下(循环比第一部分快)除了一个线程之外的所有线程大部分时间什么都不做.

    如果您确实需要主线程位于并行区域之外,这可能有效(未经测试):

    #pragma omp parallel num_threads(2)
    {
        #pragma omp master
        { /* work for master thread, other thread is NOT waiting */ }
            #pragma omp single
            {
                #pragma omp parallel for num_threads(8) schedule(static, 1)
                for (int i = 0; i < N; ++i) { /* ... */ }
            }
    }
    

    不能保证master 线程也不会计算single 区域,但如果您的内核没有过度占用,至少应该不太可能。甚至可以争辩说,如果来自外部并行区域的第二个线程没有及时到达单个区域,那么主线程也有机会进入那里会更好,即使这意味着第二个线程没有无事可做。

    由于single 区域的末尾应该只有一个隐式屏障,而master 区域不包含任何隐式屏障,只要master 区域在其中,它们就应该潜在地并行执行single 区域的前面。这假设single 区域实现良好,这样每个线程都有机会计算它。我认为,标准并不能保证这一点。

    编辑: 这些解决方案需要嵌套并行性才能工作,在大多数实现中默认禁用。可以通过环境变量OMP_NESTED或者调用omp_set_nested()来激活。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-19
      • 1970-01-01
      • 1970-01-01
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多