pero do threading library incluso tiene que preocuparse por la asignación de hilos a los núcleos. ¿No es este un trabajo del sistema operativo? Entonces, ¿cuál es la verdadera ventaja de usar TBB sobre Boost?
Tiene razón, una biblioteca de subprocesos generalmente no debería importar mapear hilos a núcleos. Y TBB no. TBB opera con tareas, no con hilos. El planificador de TBB utiliza todos los núcleos asignando un grupo de subprocesos y permitiendo que seleccione dinámicamente las tareas que se ejecutarán. Esta es la principal ventaja sobre Boost, con la que deberá asignar el trabajo disponible a los hilos manualmente. Y luego TBB ofrece construcciones de alto nivel como parallel_for, parallel_pipeline, etc. que se pueden usar para expresar los patrones paralelos más comunes y ocultar toda la manipulación con tareas.
Por ejemplo, tomemos un trozo de código que calcula los puntos de Mandelbrot (tomado de http://warp.povusers.org/Mandelbrot/, la inicialización de la variable omitida):
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); }
}
}
Ahora para que sea paralela a TBB, todo lo que necesita es convertirlas el bucle más externo en tbb :: parallel_for (yo uso una lambda C++ 11 por razones de brevedad):
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 distribuirá de forma automática todas las iteraciones del bucle más núcleos disponibles (y no molestar a cuántos) y dinámicamente equilibrar la carga por lo que t Si algún hilo tiene más trabajo que hacer, otros hilos no solo lo esperan sino que ayudan, maximizando la utilización de la CPU. Intente implementarlo con subprocesos sin procesar, y sentirá la diferencia :)
Puede establecer afinidades de subprocesos usando pthread también (por ejemplo, usando la llamada pthread_setaffinity_np) –
@Foo sí están en lo cierto. mi punto es cuánto de práctico es hacer eso. Como programador, es posible que no desee tener una tarea de programación de hilos en su aplicación. Entonces, ¿por qué TBB lo muestra como una diferenciación sobre otra biblioteca? – David
existe una ventaja observable para elegir correctamente los núcleos para las aplicaciones. Tome el ejemplo simple de un registrador roscado. Un hilo recibe datos de una interfaz de red y lo coloca en un anillo; el otro hilo se lee del anillo y escribe en un archivo (esto ayuda a aliviar la congestión que se ve si usa tcpdump). En este caso, en un sistema de procesador dual, establecer afinidades en la misma CPU es notablemente más eficiente.Si tiene hyperthreading habilitado, usar el par de núcleos virtuales es mucho más rápido. Sin embargo, esto requiere mucha microgestión, que TBB no requiere. –