c++: OpenMP y contenedores STL de acceso no aleatorio: una posible solución alternativa

Entonces, en SO y en Internet en general, hay mucha confusión y frustración acerca de cómo hacer que OpenMP sea fácil de usar. #pragma Las directivas cooperan con los contenedores STL igualmente fáciles de usar de C++.

Todo el mundo habla de soluciones alternativas para STL vector, pero ¿qué pasa con el acceso no aleatorio / contenedores bidireccionales, como map, list, set, etc.?

Encontré este problema e ideé una solución muy simple y obvia. Lo presento aquí para STL map, pero es claramente generalizable.

Versión de serie:

for (std::map<A,B>::iterator it = my_map.begin();
        it != my_map.end();
        ++it)       
    { /* do work with  it   */  }

Mi solución propuesta para usar OpenMP con STL map:

    //make an array of iterators.
    int loop_length = my_map.size();
    std::map<A,B>::iterator loop_array[ loop_length ];

    std::map<A,B>::iterator allocate_it = my_map.begin();
    for (int j=0; j<loop_length; ++j)
        loop_array[j] = allocate_it++;

    // now you can use OpenMP as usual:
    #pragma omp parallel for
    for (uint j=0; j<loop_length; ++j) 
       { /* do work with    loop_array[j]    */  }

Sin embargo, estoy lejos de ser un experto en OpenMP, así que Me gustaría saber si mi solución alternativa propuesta es eficiente y una buena práctica.

Suponga que el programador es responsable del manejo seguro de subprocesos del contenedor STL dentro del ciclo for.

Finalmente, ¿es mi solución propuesta más eficiente que la siguiente solución comúnmente propuesta? (ver respuesta a esta pregunta SO), porque, en mi solución, ¿cada subproceso no itera sobre todo el contenedor?

#pragma omp parallel
{
    for (std::map<A,B>::iterator it = my_map.begin();
            it != my_map.end();
            ++it) 
    #pragma single nowait
       {   /*  do work  */   }

}

preguntado el 03 de mayo de 12 a las 15:05

Sospecho que esto es más rápido (al menos cuando A y B son grandes, de lo contrario, podría simplemente copiarlos en un vector). ¿Pero lo has probado en tu problema? ¿Fue más rápido? -

@larsmans No he realizado ninguna prueba de rendimiento, y realmente tampoco planifico (lo siento). Ya tengo un programa grande y sofisticado escrito en serie, con contenedores STL en todas partes, y estoy tratando de ejecutar varios subprocesos para ciertos STL-for-loops. Como tal, no puedo aislarlo y cronometrarlo fácilmente... -

Ni siquiera si copias el contenido de los contenedores en un vector con fines de prueba? -

Lo siento si mi pregunta es estúpida, pero ¿no podrías simplemente iterar sobre j y luego acceder a los elementos a través de allocate_it+j donde asignarlo se establece como en su publicación. -

@ Azrael3000 Pero la aritmética de iteradores no es solo válida para iteradores de acceso aleatorio (como para vector)? map , list, set, solo use iteradores bidireccionales. -

1 Respuestas

OpenMP proporciona la task construir a partir de la versión 3.0, que es bastante útil para usar con STL:

for (std::map<A,B>::iterator it = my_map.begin();
        it != my_map.end();
        ++it)       
{
   #pragma omp task
   { /* do work with  it   */  }
}

Por supuesto, las dependencias de datos entre iteraciones no deberían existir para que esto funcione.

contestado el 04 de mayo de 12 a las 23:05

¿Hay una sobrecarga adicional por tener el comando OpenMP dentro del ciclo? En general, pensé que el rendimiento se mejora mejor al paralelizar la sección de código más grande posible (por ejemplo, el bucle más externo en los bucles anidados). - cmo

Eso es generalmente cierto, pero usando omp for en el bucle for requiere iteradores rápidos de acceso aleatorio (por ejemplo, que se ejecutan en tiempo constante). Hasta donde yo sé, std::map no proporciona un iterador de acceso aleatorio y debería simular uno. - cristo iliev

Sí, eso es lo que estaba tratando de hacer en mi "solución propuesta", al crear la matriz convencional (de acceso aleatorio) y luego hacer un bucle para eso en lugar del mapa directamente. Solo me preocupaba que su método generara demasiada sobrecarga (administración de subprocesos en cada iteración). - cmo

OpenMP no crea hilos separados para cada tarea. Por el contrario, las tareas se ponen en una "bolsa" y luego cada subproceso roba una tarea. La investigación de mis colegas muestra que la sobrecarga es casi insignificante, mientras que la codificación se simplifica enormemente. No estoy tratando de persuadirlo para que use tareas, solo intente ver cuál es más rápido y cuál requiere más programación. - cristo iliev

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.