3

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

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

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

}

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

4

1 回答 1

7

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

既然你在 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 并不是我向新程序员推荐的。我真的建议只对并行化微不足道的代码进行并行化,直到您对线程有非常牢靠的把握。为此,我建议使用openmpwhich 从 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(-fopenmp对于gcc,/openmp对于visual c++)。正如您所看到的,它使用起来相当简单(对于这样简单的用例,更复杂的场景是另一回事)然后 tbb 并且具有在不支持 openmp 或 tbb 的平台上工作的额外好处(因为未知#pragmas被忽略由编译器)。就我个人而言,我在某些项目中使用 openmp 来支持 tbb,因为我无法使用它的开源许可证,并且购买 tbb 对于这些项目来说有点陡峭。

既然我们已经知道了如何使循环并行化,那么让我们来看看它是否值得。这是一个确实不容易回答的问题,因为它完全取决于您处理的元素数量以及您的程序预期运行的平台类型。你的问题是带宽很重,所以我不会指望性能有很大的提高。

  • 如果您只处理1000元素,则循环的并行版本很可能会因为开销而比单线程版本慢。
  • 如果您的数据不在缓存中(因为它不适合)并且您的系统非常缺乏带宽,您可能看不到太多好处(尽管您可能会看到一些好处,但如果它1.X即使您使用很多处理器也是如此)
  • 如果您的系统是 ccNUMA(可能用于多路系统),则无论元素数量如何,您的性能都可能会降低,因为额外的传输成本
  • 编译器可能会错过关于指针别名的优化(因为循环体被移动到不同的函数)。使用__restrict(对于 gcc,对于 vs 没有线索)可能有助于解决这个问题。
  • ...

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

于 2011-12-29T16:23:06.650 回答