しかし、スレッディングライブラリは、コアへのスレッドの割り当てについても心配する必要があります。これはオペレーティングシステムの仕事ではありませんか?ブーストよりもTBBを使う本当のBenifitは何ですか?
スレッドライブラリは通常、スレッドをコアにマッピングする必要はありません。 TBBはそうではありません。 TBBはスレッドではなくタスクで動作します。 TBBのスケジューラは、スレッドのプールを割り当て、実行するタスクを動的に選択させることによって、すべてのコアを利用します。これは、利用可能な作業をスレッドに手動でマッピングする必要があるBoostに勝る主な利点です。そして、TBBは、最も一般的な並列パターンを表現するために使用できるparallel_for、parallel_pipelineなどの高水準構造を提供し、タスクによるすべての操作を非表示にします。例えば
、のは、マンデルブロフラクタルのポイントを算出するコードの一部を見てみましょう(http://warp.povusers.org/Mandelbrot/から取られ、変数の初期化は省略):
今
for(unsigned y=0; y<ImageHeight; ++y)
{
double c_im = MaxIm - y*Im_factor;
for(unsigned x=0; x<ImageWidth; ++x)
{
double c_re = MinRe + x*Re_factor;
double Z_re = c_re, Z_im = c_im;
bool isInside = true;
for(unsigned n=0; n<MaxIterations; ++n)
{
double Z_re2 = Z_re*Z_re, Z_im2 = Z_im*Z_im;
if(Z_re2 + Z_im2 > 4)
{
isInside = false;
break;
}
Z_im = 2*Z_re*Z_im + c_im;
Z_re = Z_re2 - Z_im2 + c_re;
}
if(isInside) { putpixel(x, y); }
}
}
はそれがTBBと平行にするために、あなたが必要なのは、変換することですTBBへの最も外側のループ:: parallel_forは(私は簡潔にするためにC++ 11のラムダを使用):
tbb::parallel_for(0, ImageHeight, [=](unsigned y)
{
// the rest of code is exactly the same
double c_im = MaxIm - y*Im_factor;
for(unsigned x=0; x<ImageWidth; ++x)
{
...
// if putpixel() is not thread safe, a lock might be needed
if(isInside) { putpixel(x, y); }
}
});
TBBは、自動的に利用可能なコアを超えるすべてのループ反復を配布します(とどのように多くのあなたが気にしない)と動的負荷とのバランスを取るもし他のスレッドが待つだけではなく、CPU使用率を最大にするのに役立ちます。生スレッドで実装しようとすると、違いが感じられます。
pthreadを使用してスレッドの親和性を設定することもできます(例:pthread_setaffinity_np呼び出しを使用) –
@Fooはいです。私の要点は、それを実践するのがどれだけのものかということです。プログラマーとしては、アプリケーションでスレッドスケジューリングタスクを実行させたくないかもしれません。だからTBBが他の図書館と差別化しているのはなぜですか? – David
アプリケーション用にコアを適切に選択することには、目に見える利点があります。スレッド化されたロガーの簡単な例を見てみましょう。 1つのスレッドは、ネットワークインタフェースからデータを受信し、それをリング上に置く。もう一方のスレッドはリングから読み取り、ファイルに書き込みます(これは、tcpdumpを使用する場合に表示される輻輳を緩和するのに役立ちます)。この場合、デュアルプロセッサシステムでは、同一CPU上の親和性の設定がより効率的に行われます。ハイパースレッディングを有効にしている場合は、仮想コアのペアを使用する方がはるかに高速です。しかし、これには多くのマイクロ管理が必要であり、TBBには必要ありません。 –