2012-11-04 5 views
11
vector<int> v; 

#pragma omp parallel for ordered schedule(dynamic, anyChunkSizeGreaterThan1) 
    for (int i = 0; i < n; ++i){ 
      ... 
      ... 
      ... 
#pragma omp ordered 
      v.push_back(i); 
    } 

Questo riempie v con un elenco ordinato di dimensioni n.Come funziona la clausola ordinata omp?

Quando si raggiunge il blocco omp ordered, tutti i thread devono attendere il completamento del thread di iterazione più basso, ma cosa accadrebbe se nessuno dei thread fosse stato nominato per tale iterazione specifica? Oppure la libreria di runtime di OpenMP si assicura sempre che l'iterazione più bassa venga gestita da qualche thread?

Inoltre, perché è consigliabile utilizzare la clausola ordered insieme allo dynamic schedule? static schedule influire sulle prestazioni?

risposta

31

La clausola ordered funziona così: diversi thread eseguono contemporaneamente fino incontrano regione ordered, che viene poi eseguito in sequenza nello stesso ordine come sarebbe ottenere eseguito in un loop seriale. Ciò consente ancora un certo grado di concorrenza, soprattutto se la sezione di codice all'esterno della regione ordered ha un tempo di esecuzione sostanziale.

Non vi è alcun motivo particolare per utilizzare la pianificazione dynamic anziché la pianificazione static con piccole dimensioni del blocco. Tutto dipende dalla struttura del codice. Poiché ordered introduce la dipendenza tra i thread, se utilizzato con schedule(static) con dimensioni di blocco predefinite, il secondo thread dovrebbe attendere che il primo completi tutte le iterazioni, quindi il terzo thread dovrebbe attendere che il secondo termini le iterazioni (e quindi anche per il primo), e così via. Si potrebbe facilmente visualizzare con 3 fili e 9 iterazioni (3 per thread):

tid List of  Timeline 
    iterations 
0 0,1,2  ==o==o==o 
1 3,4,5  ==.......o==o==o 
2 6,7,8  ==..............o==o==o 

= mostra che il filo viene eseguito codice in parallelo. o è quando il thread sta eseguendo la regione ordered. . è il thread inattivo, in attesa del suo turno per eseguire la regione ordered. Con schedule(static,1) accadrebbe quanto segue:

tid List of  Timeline 
    iterations 
0 0,3,6  ==o==o==o 
1 1,4,7  ==.o==o==o 
2 2,5,8  ==..o==o==o 

Credo che la differenza in entrambi i casi è più che evidente. Con schedule(dynamic) le immagini sopra diventerebbero più o meno casuali in quanto l'elenco delle iterazioni assegnate a ciascun thread non è deterministico. Inoltre, aggiungerebbe un ulteriore sovraccarico. È utile solo se la quantità di calcolo è diversa per ogni iterazione e richiede molto più tempo per eseguire il calcolo rispetto all'overhead aggiunto dell'utilizzo della pianificazione dinamica.

Non preoccuparti dell'iterazione con il numero più basso. Di solito viene gestito nel primo thread del team per essere pronto per eseguire il codice.

+0

Ottima risposta Hristo! Tutto chiaro ora, grazie! –

+2

@ Cookie503, notare che se la dimensione del blocco è troppo piccola, la memorizzazione nella cache potrebbe risultare meno utile a causa della località di dati persi. Ciò potrebbe danneggiare la tua performance molto peggio della serializzazione implicita. Sperimenta diverse dimensioni del blocco fino a ottenere la migliore accelerazione. Usa i loop 'ordered' saggiamente e se possibile li eludono, anche se questo porta ad un maggiore footprint di memoria - ad es. (dato il tuo esempio particolare) dovrebbe essere usato un semplice array preallocato (o un altro contenitore ad accesso casuale thread-safe) invece di un vettore: 'arr [i] = i;' –