gpt4 book ai didi

c++ - 使用 TBB 的非常基本的 for 循环

转载 作者:太空狗 更新时间:2023-10-29 20:29:54 25 4
gpt4 key购买 nike

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

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

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

}

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

最佳答案

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

因为你在待定中要求它:

首先您需要在某处初始化库(通常在您的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(-fopenmp 用于 gcc,/openmp 用于 visual c++)。正如您所看到的,它比 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com