但是線程庫甚至需要擔心線程分配給內核。這不是操作系統的工作嗎?那麼使用TBB優於Boost的真正好處是什麼?
你說得對,線程庫通常不應該關心將線程映射到內核。而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 yes是正確的。我的觀點是有多少實際用途是這樣做的。作爲程序員,您可能不希望在應用程序中完成線程調度任務。那麼爲什麼TBB將其視爲與其他圖書館的區別? – David
正確選擇應用程序的內核有一個明顯的優勢。以線程記錄器的簡單示例爲例。一個線程從網絡接口接收數據並將其放置在一個環上;另一個線程從環中讀取數據並寫入文件(這有助於緩解您在使用tcpdump時看到的擁塞)。在這種情況下,在雙處理器系統上,在同一CPU上設置親和性顯然更有效。如果啓用了超線程,則使用虛擬內核對要快得多。但是,這需要很多微觀管理,而TBB並不需要這些。 –