我想并行化一个循环(使用tbb
),其中包含一些昂贵但可矢量化的迭代(随机扩展)。我的想法是缓冲这些并刷新缓冲区,只要它达到矢量大小。这样的缓冲区必须是线程本地的。例如,并行循环结束时使用TBB刷新线程本地缓冲区
// dummy for testing
void do_vectorized_work(size_t k, size_t*indices)
{}
// dummy for testing
bool requires_expensive_work(size_t k)
{ return (k&7)==0; }
struct buffer
{
size_t K=0, B[vector_size];
void load(size_t i)
{
B[K++]=i;
if(K==vector_size)
flush();
}
void flush()
{
do_vectorized_work(K,B);
K=0;
}
};
void do_work_in_parallel(size_t N)
{
tbb::enumerable_thread_specific<buffer> tl_buffer;
tbb::parallel_for(size_t(0),N,[&](size_t i)
{
if(requires_expensive_work(i))
tl_buffer.local().load(i);
});
}
然而,这留下缓冲区非空的,所以我还是要最后一次刷新他们每个人的
for(auto&b:tl_buffer)
b.flush();
但这是串行!当然,我也可以尝试这样做并行
using tl_range = typename tbb::enumerable_thread_specific<buffer>::range_type;
tbb::parallel_for(tl_buffer.range(),[](tl_range const&range)
{
for(auto r:range)
r->flush();
});
但我不知道这是有效的(因为只有尽可能多的缓冲区有线程)。我想知道是否有可能避免事件发生后的最后冲洗。即是否可以使用tbb::task
s(替换tbb::parallel_for
),以便每个线程的最终任务是刷新其缓冲区?
感谢您的支持。我不认为异步方法比我在OP中描述的尝试更好。使用'tbb :: task_scheduler_observer'的方法听起来很有趣。你可以使用代码片段概述这将如何工作? – Walter
@Walter更新。虽然我只在线上编译器上尝试过,但是它并没有与当地观察员进行最近的TBB测试:http://coliru.stacked-crooked.com/a/11728cd935579cfe – Anton