2012-03-31 3 views
6

Sto provando a mettere in parallelo un programma che sto usando e ho ottenuto la seguente domanda. Avrò una perdita di prestazioni se più thread devono leggere/scrivere sullo stesso vettore ma diversi elementi del vettore? Ho la sensazione che questo sia il motivo per cui il mio programma difficilmente diventa più veloce nel parallelizzarlo. Prendere il seguente codice:Vettori condivisi in 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; 

} 

Ovviamente il vero programma fa operazioni molto più costosi, ma questo esempio deve solo spiegare la mia domanda. Quindi, il ciclo for può essere eseguito in modo rapido e completamente parallelo oppure i vari thread devono attendere reciprocamente perché solo un thread alla volta può accedere al numero di vettore, ad esempio sebbene stiano tutti leggendo elementi diversi del vettore?

Stessa domanda con l'operazione di scrittura: ho bisogno del pragma critico o non è un problema poiché ogni thread scrive in un diverso elemento dei risultati del vettore? Sono contento di ogni aiuto che posso ottenere ed inoltre sarebbe bello sapere se esiste un modo migliore per farlo (forse non utilizzare i vettori, ma semplici array e puntatori, ecc.) Ho anche letto i vettori aren in alcuni casi è sicuro usare thread: OpenMP and STL vector

Grazie mille per il vostro aiuto!

risposta

7

Immagino che la maggior parte dei problemi con i vettori in più thread sarebbe se deve ridimensionare, quindi copia l'intero contenuto del vettore in un nuovo posto in memoria (un pezzo più grande assegnato) che se sei accedendo a questo in parallelo, hai appena provato a leggere un oggetto che è stato cancellato.

Se non si sta ridimensionando la matrice, poi ho avuto mai avuto alcun problema con simultaneo in lettura scrive nel vettore (ovviamente a patto che non sto scrivendo due volte lo stesso elemento)

Per quanto riguarda la mancanza di potenziamento delle prestazioni, la sezione critica di openmp rallenterà il tuo programma probabilmente allo stesso modo di usare solo 1 thread (a seconda di quanto viene effettivamente fatto al di fuori di quella sezione critica)

Puoi rimuovere l'istruzione della sezione critica (con le condizioni sopra in mente).

+0

Lui non ridimensiona il vettore a tutti. – eudoxos

+0

@eudoxos Mi rendo conto che dal frammento di codice, volevo solo assicurarmi che fosse menzionato, specialmente da quando ha rilevato il fatto che i vettori STL non sono thread-safe in determinate condizioni – SirGuy

+0

+1: non arriva davvero qui, ma devi tenere a mente che le operazioni specifiche del vettore come accodamento, ridimensionamento, ecc. non sono thread-safe e probabilmente si rompono.Ma funzionare solo sugli elementi di un vettore va bene fintanto che ogni elemento viene scritto da un solo thread. –

5

Non si ottiene alcuna accelerazione proprio a causa del sectino critico, che è superfluo, dal momento che gli stessi elementi non saranno mai modificati allo stesso tempo. Rimuovere il pezzo di sezione critico e funzionerà bene.

Puoi anche giocare con la strategia di pianificazione, perché se l'accesso alla memoria non è lineare (è nell'esempio che hai dato), i thread potrebbero combattere per la cache (scrivendo elementi nella stessa linea della cache). OTOH se il numero di elementi è dato come nel tuo caso e non vi è alcuna ramificazione nel loop (quindi verranno eseguiti all'incirca alla stessa velocità), static, che è l'IIRC di default, dovrebbe funzionare comunque al meglio.

(BTW è possibile dichiarare x all'interno del ciclo per evitare private(x) e la direttiva shared è implicito IIRC (non ho mai usato).)

+0

+1; se non stai ridimensionando o accodando o hai un vettore, è solo un array 1d, e OpenMP è molto bravo a operare sugli array. Per quanto riguarda static, private, ecc, penso che "best practice" sia usare default (nessuno) e rendere tutto esplicitamente privato o condiviso, solo per essere esplicito, e come sottolinea @eudoxos, avendo variabili definite nell'ambito del parallelismo la sezione li rende implicitamente privati ​​e quindi è un po 'più facile seguire il codice. –

+0

Ciao grazie per il tuo aiuto. È davvero più veloce dichiarare x all'interno del ciclo (ogni thread lo dichiarerà allora, a destra) piuttosto che prima del ciclo come sopra, o è lo stesso rendimento saggio, ma è solo più bello da guardare? Cosa significa che l'accesso alla memoria non è lineare e perché è così? – user1304680

+0

@ user1304680: la dichiarazione è per il compilatore, dice solo che si desidera avere un pezzo di memoria di una certa dimensione e chiamarlo in qualche modo nel codice successivo. Dubito fa la differenza per qualsiasi compilatore decente e moderatamente ottimizzante. Accesso non lineare: intendevo l'accesso casuale agli elementi dai thread nelle regioni di memoria adiacenti. La RAM serve quindi un pezzo di memoria alla CPU, che è più grande della voce vettoriale. Se 2 core accedono a parti di RAM nelle vicinanze, potrebbero trovarsi nella stessa riga della cache e verranno quindi sincronizzati sul livello hw, ma lo renderà più lento. Non preoccuparti di questo finché non ne hai bisogno. – eudoxos