use*_*710 0 c++ concurrency vector tbb c++11
我对两个用来自梅森扭曲器的伪随机整数填充给定向量的程序进行了一些比较,重点是 TBB 版本非常慢,当 TBB 需要时,std 版本在大约 0.6 秒内执行任务至少1.1秒。
我还注意到 TBB 并没有真正提供优化的算法来处理容器,但它只提供通用构造(parallel_for、parallel_for_each 和类似的)来处理通用任务,其中 std 提供的在这种情况下std::generate
是一个更好、更干净的解决方案。
你可以在这里下载我的小测试,其中包含 2 个小源文件 + gcc 的 Makefile http://www.sendspace.com/file/ew73h8
我在这里做错了什么?我增加这个向量的大小越多,TBB 就越慢,我使用的是 Ubuntu 13.04 64 位和 Intel Q6600。
TBB 版本在某些方面可以做得更好吗?
编辑:这两个文件的完整源代码
配置文件
#define N 10000000
Run Code Online (Sandbox Code Playgroud)
标准cpp
#include <random>
#include <iostream>
#include <vector>
#include <algorithm>
#include "config.hpp"
int main() {
std::vector<u_int32_t> v(N);
std::mt19937 mt;
std::uniform_int_distribution<u_int32_t> dist(0,499);
std::generate(v.begin(),v.end(),[&]{return dist(mt);});
return(0);
}
Run Code Online (Sandbox Code Playgroud)
待定.cpp
#include <tbb/concurrent_vector.h>
#include <tbb/parallel_for_each.h>
#include <random>
#include <iostream>
#include "config.hpp"
int main()
{
tbb::concurrent_vector<u_int32_t> v(N);
std::mt19937 mt;
std::uniform_int_distribution<u_int32_t> dist(0, 499);
tbb::parallel_for_each(v.begin(),v.end(),[&](u_int32_t& e){e = dist(mt); });
return(0);
}
Run Code Online (Sandbox Code Playgroud)
您正在为 ITBB 将控制的所有工作人员共享随机数生成器(RNG),正如我从您的问题中看到的那样,这将是四个。暂且不谈从多个线程改变 RNG 状态的线程安全问题,我会指出对缓存的影响:RNG 状态使用的同一内存可从四个处理器进行读写访问,这很可能是使缓存无用。
让我们试试这个:
#include <tbb/concurrent_vector.h>
#include <tbb/parallel_for_each.h>
#include <vector>
#include <functional>
#include <random>
#include <iostream>
#include "config.hpp"
static thread_local std::mt19937 mt;
static thread_local std::uniform_int_distribution<u_int32_t> dist(0, 499);
int main()
{
std::vector<u_int32_t> v(N);
auto f = [&v](std::pair<u_int32_t, u_int32_t> const& p) {
for (size_t i=p.first; i < p.second; i++)
{
v[i] = dist( mt );
}
};
std::vector< std::pair< u_int32_t, u_int32_t > > work;
work.push_back( std::make_pair( 0, N/2) );
work.push_back( std::make_pair( N/2, N) );
tbb::parallel_for_each(
work.begin(),
work.end(),
f
);
return(0);
}
Run Code Online (Sandbox Code Playgroud)
现在时间减少到标准版本的近一半(我只有双核)。该代码的作用是强制 itbb 在连续的内存块中工作,而不是分配数据,而是分配工作分配。我不认为这是使用 ITBB 的最佳方式,但另一方面,parallel_for_each 不能提供块大小(从我在文档中看到的),而使用 *parallel_for* 来实现它需要一些研究。但这并不那么困难:
#include <tbb/concurrent_vector.h>
#include <tbb/parallel_for.h>
#include <vector>
#include <functional>
#include <random>
#include <iostream>
#include "config.hpp"
static thread_local std::mt19937 mt;
static thread_local std::uniform_int_distribution<u_int32_t> dist(0, 499);
int main()
{
std::vector<u_int32_t> v(N);
auto f = [&v](const tbb::blocked_range<u_int32_t>& p) {
for (auto i=p.begin(); i < p.end(); i++)
{
v[i] = dist( mt );
}
};
tbb::parallel_for(
tbb::blocked_range<u_int32_t>(0,N),
f
);
return(0);
}
Run Code Online (Sandbox Code Playgroud)
您可能不想使用 ITBB,而是想在 OpenMP 中使用一些并行构造,无论如何,OpenMP 已与 gcc 捆绑多年(并且您仍然可以将 ITBB 与 OpenMP 一起使用,但要小心)。
随机数和并行代码怎么样?他们很乱。如果您想独立为 RNG 提供种子并用于时钟,上面的代码可能就足够了。如果您想要获得可重现的结果和不相关的 RNG,那么您必须注意由特定于线程的种子初始化的每个生成器,并且您还需要一种让每个种子通过其线程接触确定性部分的方法工作的...
归档时间: |
|
查看次数: |
4866 次 |
最近记录: |