2012-03-31 44 views
6

Estoy intentando paralizar un programa que estoy usando y recibí la siguiente pregunta. ¿Obtendré una pérdida de rendimiento si múltiples hilos necesitan leer/escribir en el mismo vector pero diferentes elementos del vector? Tengo la sensación de que esa es la razón por la cual mi programa apenas se acelera al paralizarlo. Tome el siguiente código:Vectores compartidos en OpenMP

#include <vector> 

int main(){ 

    vector<double> numbers; 
    vector<double> results(10); 
    double x; 

    //write 10 values in vector numbers 
    for (int i =0; i<10; i++){ 
     numbers.push_back(cos(i)); 
    } 

#pragma omp parallel for \ 
    private(x) \ 
    shared(numbers, results) 
     for(int j = 0; j < 10; j++){ 

      x = 2 * numbers[j] + 5; 
#pragma omp critical // do I need this ? 
      { 
       results[j] = x;  
      } 
     } 

    return 0; 

} 

Obviamente el programa real hace operaciones mucho más caros, pero este ejemplo se única explicar mi pregunta. Entonces, ¿el bucle for se puede hacer rápido y completamente en paralelo o los diferentes hilos tienen que esperar el uno al otro porque solo un hilo a la vez puede acceder al número del vector, por ejemplo, aunque todos leen diferentes elementos del vector?

La misma pregunta con la operación de escritura: ¿Necesito el pragma crítico o no hay problema ya que cada hilo escribe en un elemento diferente de los resultados del vector? Estoy contento con cada ayuda que puedo obtener y también sería bueno saber si hay una mejor manera de hacerlo (tal vez no use vectores en absoluto, sino matrices y punteros simples, etc.) También leo vectores aren 'th thread safe' en ciertos casos y se recomienda utilizar un puntero: OpenMP and STL vector

¡Muchas gracias por su ayuda!

Respuesta

7

Me imagino que la mayoría de los problemas con vectores en múltiples hilos serían si tiene que cambiar el tamaño, luego copia todo el contenido del vector en un nuevo lugar en la memoria (un trozo asignado más grande) que si accediendo a esto en paralelo, entonces usted acaba de tratar de leer un objeto que ha sido eliminado.

Si no cambie el tamaño de la matriz, entonces he tenido nunca tuvo ningún problema con la lectura simultánea escribe en el vector (obviamente, siempre y cuando no estoy escribiendo dos veces el mismo elemento)

cuanto a la falta de aumento de rendimiento, la sección crítica de openmp reducirá la velocidad de su programa hasta probablemente lo mismo que usar 1 hilo (dependiendo de cuánto se hace realmente fuera de esa sección crítica)

Puede eliminar la declaración de la sección crítica (con las condiciones arriba en mente).

+0

Él no cambia el tamaño del vector en absoluto. – eudoxos

+0

@eudoxos Me doy cuenta de que desde el fragmento de código, solo quería asegurarme de que se mencionara, especialmente desde que mencionó el hecho de que los vectores STL no son seguros para subprocesos bajo ciertas condiciones – SirGuy

+0

+1: realmente no aparece aquí, pero hay que tener en cuenta que las operaciones específicas del vector como agregar, cambiar el tamaño, etc. no son enhebrables y probablemente se rompan.Pero solo operar en los elementos de un vector está bien siempre y cuando cada elemento esté siendo escrito por un solo hilo. –

5

No obtiene aceleración precisamente debido al elemento crítico, que es superfluo, ya que los mismos elementos nunca se modificarán al mismo tiempo. Retire la pieza crítica de la sección y funcionará perfectamente.

También puede jugar con la estrategia de programación, porque si el acceso a la memoria no es lineal (en el ejemplo que proporcionó), los hilos pueden luchar por la caché (escribir elementos en la misma línea de caché). OTOH si el número de elementos se da como en su caso y no hay bifurcación en el bucle (por lo tanto, se ejecutarán aproximadamente a la misma velocidad), static, que es el IIRC predeterminado, debería funcionar mejor de todos modos.

(Por cierto, puede declarar x dentro del bucle para evitar private(x) y la directiva shared está implícito IIRC (Nunca utilicé).)

+0

+1; si no está redimensionando o agregando o qué tiene un vector, es solo una matriz de 1d, y OpenMP es muy bueno para operar en arreglos. En cuanto a estática, privada, etc., creo que la "mejor práctica" es usar el valor predeterminado (ninguno) y hacer que todo sea explícitamente privado o compartido, solo para ser explícito, y como @eudoxos señala, teniendo variables definidas en el alcance del paralelo sección los hace implícitamente privados y luego es un poco más fácil seguir el código. –

+0

Hola, gracias por tu ayuda. ¿Es realmente más rápido declarar x dentro del bucle (cada hilo lo declarará entonces, a la derecha) en lugar de antes del bucle como se indicó anteriormente, o tiene el mismo rendimiento en cuanto a rendimiento, pero es más agradable de ver? ¿Qué significa que el acceso a la memoria no es lineal y por qué es así? – user1304680

+0

@ user1304680: La declaración es para el compilador, simplemente dice que desea tener un trozo de memoria de algún tamaño y llamarlo de alguna manera en el código siguiente. Dudo que marque la diferencia para cualquier compilador decente y moderadamente optimizador. Acceso no lineal: quise decir acceso aleatorio a elementos de hilos en regiones de memoria adyacentes. RAM luego sirve un trozo de memoria a la CPU, que es más grande que el elemento vectorial. Si 2 núcleos acceden a las piezas de RAM cercanas, podría estar en la misma línea de caché y luego se sincronizan en el nivel de hw, pero lo hace más lento. No te preocupes hasta que lo necesites. – eudoxos