我想並行化一個循環(使用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