我是一个非常新的程序员,我对英特尔的例子有一些麻烦。我认为如果我能看到如何在 tbb 中实现最基本的可能循环会很有帮助。

for (n=0 ; n < songinfo.frames; ++n) {

         sli[n]=songin[n*2];
         sri[n]=songin[n*2+1];

}

这是我用来解交织音频数据的循环。这个循环会从 tbb 中受益吗?你将如何实现它?

最佳答案

首先,对于以下代码,我假设您的 arraysmytype* 类型,否则代码需要进行一些修改。此外,我假设您的范围不重叠,否则并行化尝试将无法正常工作(至少在没有更多工作的情况下不会)

由于您在 tbb 中要求它:

首先,您需要在某处(通常在您的 main 中)初始化库。对于代码,假设我在某处放置了 using namespace tbb

int main(int argc, char *argv[]){
   task_scheduler_init init;
   ...
}

然后您将需要一个仿函数来捕获您的数组并执行 forloop 的主体:
struct apply_func {
    const mytype* songin; //whatever type you are operating on
    mytype* sli;
    mytype* sri;
    apply_func(const mytype* sin, mytype* sl, mytype* sr):songin(sin), sli(sl), sri(sr)
    {}
    void operator()(const blocked_range<size_t>& range) {
      for(size_t n = range.begin(); n !=range.end(); ++n){
        sli[n]=songin[n*2];
        sri[n]=songin[n*2+1];
      }
    }
}

现在你可以使用 parallel_for 来并行化这个循环:
size_t grainsize = 1000; //or whatever you decide on (testing required for best performance);
apply_func func(songin, sli, sri);
parallel_for(blocked_range<size_t>(0, songinfo.frames, grainsize), func);

应该这样做(如果我没记错的话,有一段时间没有看 tbb,所以可能会有小错误)。
如果使用 c++11,则可以使用 lambda 来简化代码:
size_t grainsize = 1000; //or whatever you decide on (testing required for best performance);
parallel_for(blocked_range<size_t>(0, songinfo.frames, grainsize),
             [&](const blocked_range<size_t>&){
                for(size_t n = range.begin(); n !=range.end(); ++n){
                  sli[n]=songin[n*2];
                  sri[n]=songin[n*2+1];
                }
             });

话虽如此,tbb 并不是我向新程序员推荐的。我真的建议只并行化那些很容易并行化的代码,直到你对线程有了非常牢固的把握。为此,我建议使用 openmp,它比 tbb 开始时更简单一些,同时仍然足够强大以并行化很多东西(不过取决于支持它的编译器)。对于您的循环,它将如下所示:
#pragma omp prallel for
for(size_t n = 0; n < songinfo.frames; ++n) {
  sli[n]=songin[n*2];
  sri[n]=songin[n*2+1];
}

然后你必须告诉你的编译器编译和链接 openmp(gcc 的 -fopenmp,visual c++ 的 /openmp)。正如您所看到的,它使用起来要简单得多(对于这种简单的用例,更复杂的场景是另一回事)然后 tbb 并且具有在不支持 openmp 或 tbb 的平台上工作的额外好处(因为未知的 #pragmas 是被编译器忽略)。就我个人而言,我在某些项目中使用 openmp 来支持 tbb,因为我无法使用它的开源许可证,并且购买 tbb 对这些项目来说有点陡峭。

现在我们知道了如何并行化循环,让我们来看看它是否值得。这是一个真的不容易回答的问题,因为它完全取决于您处理的元素数量以及您的程序预计运行的平台类型。你的问题是带宽很重,所以我不会指望性能有很大提高。
  • 如果您只处理 1000 元素,由于开销,循环的并行版本很可能比单线程版本慢。
  • 如果您的数据不在缓存中(因为它不适合)并且您的系统非常缺乏带宽,您可能看不到太多好处(尽管您可能会看到一些好处,但如果即使您使用很多处理器,它也按 1.X 的顺序排列)
  • 如果您的系统是 ccNUMA(可能用于多路系统),无论元素数量如何,您的性能都可能会下降,因为额外的传输成本
  • 编译器可能会错过有关指针别名的优化(因为循环体被移动到不同的函数中)。使用 __restrict(对于 gcc,对于 vs 没有线索)可能有助于解决这个问题。
  • ...

  • 就我个人而言,我认为您最有可能看到性能显着提升的情况是,如果您的系统具有单个多核 cpu,则数据集适合 L3 缓存(而不是单个 L2 缓存)。对于更大的数据集,您的性能可能会提高,但不会提高太多(正确使用预取可能会获得类似的 yield )。当然,这纯粹是推测。

    关于c++ - 使用 TBB 的非常基本的 for 循环,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8664248/

    10-13 01:18