I um eine Schleife parallelisieren sollen (mit tbb
), die einige, aber teuer vektorisierbar Iterationen enthält (zufällig verteilt). Meine Idee war, diese zu puffern und den Puffer zu leeren, wenn die Vektorgröße erreicht ist. Ein solcher Puffer muss Thread-lokal sein. Zum BeispielSpülung Gewinde lokale Puffer am Ende der parallelen Schleife mit 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);
});
}
Dies lässt jedoch die Puffer nicht leer ist, so habe ich noch jede von ihnen ein letztes Mal
for(auto&b:tl_buffer)
b.flush();
aber das ist seriell zu spülen! Natürlich kann ich auch parallel
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();
});
versuchen, dies zu tun, aber ich bin nicht sicher, dass dies effizient ist (da es nur so viele Puffer wie es Threads). Ich habe mich gefragt, ob es möglich ist, diesen letzten Flush nach dem Event zu vermeiden. I.e. ist es möglich, tbb::task
s zu verwenden (tbb::parallel_for
ersetzt) in der Weise, dass die letzte Aufgabe jedes Threads seinen Puffer zu leeren ist?
Danke dafür. Ich denke nicht, dass der asynchrone Ansatz besser ist als meine im OP beschriebenen Versuche. Die Methode mit dem 'tbb :: task_scheduler_observer 'klingt interessant. Können Sie mit einem Code-Snippet beschreiben, wie das funktioniert? – Walter
@Walter aktualisiert. Obwohl ich es nur auf on-line-Compiler versuchte, der nicht genug genug TBB mit lokalem Beobachter hat: http://coliru.stacked-crooked.com/a/11728cd935579cfe – Anton