2012-11-14 86 views
0

我正在編寫一些代碼來並行處理碰撞,預期的結果是每個線程都有一個加速,但是我沒有在數據處理中獲得任何加速,因爲我在裏面有一個關鍵部分parallel_reduce(),我相信它的序列化過多的訪問對象。這是代碼的外觀:並行處理碰撞對

do { 
    totalVel = 0.; 
#pragma omp parallel for 
    for (unsigned long i = 0; i < bodyContact.size(); i++) { 
     totalVel += bodyContact.at(i).bodyA()->parallel_reduce(); 
     totalVel += bodyContact.at(i).bodyB()->parallel_reduce(); 
    } 
} while (totalVel >= 0.00001); 

有沒有辦法通過使其並行或訪問序列化得到更多的速度?

觀察:

  • bodyA()bodyB()是重複自己的bodyContact容器內的大量的物體。
  • 現在parallel_reduce()只做一個乘法(臨界區),但會變得更加複雜。
double parallel_reduce(){ 
    #pragma omp critical 
     this->vel_ *= 0.99; 
     return vel_.length(); 
    }

實際時間:

  • 串行,25.635
  • 平行,123.559
+1

如果'parallel_reduce()'是你的瓶頸,那麼這就是你的工作。也許張貼它的身體和人們可以幫助。這裏沒有祕密武器! –

+0

關鍵區域的並行循環基本上只是一個串行循環,並且有很多額外的開銷,並且它並不令我感到驚訝。告訴我們更多關於bodyContact.at(i).bodyA()和.bodyB()中的this->他們都是獨立的,還是會有一些As和一些Bs重疊? –

+0

他們會重疊很多。並且parallel_reduce()的實際代碼並不像它應該有什麼區別那麼重要,還有其他方法可以讓代碼變得更慢,以便區別它們嗎? –

回答

0

上面很可能不僅慢,但很可能是錯誤的;所有的線程都試圖更新相同的totalVel。競爭條件,而且還爭,緩存失效等

假設parallel_reduce()東西是好的噸,你會喜歡的東西更像

do { 
    totalVel = 0.; 
#pragma omp parallel for default(none) shared(bodyContact) reduction(+:totalVel) 
    for (unsigned long i = 0; i < bodyContact.size(); i++) { 
     totalVel += bodyContact.at(i).bodyA()->parallel_reduce(); 
     totalVel += bodyContact.at(i).bodyB()->parallel_reduce(); 
    } 
} while (totalVel >= 0.00001); 

這將正確地做totalVelreduction

+0

是的,但它仍然比串行版本慢。 double parallel_reduce() { #pragma omp critical this-> vel_ * = 0.99; return vel_.length(); } 這就是parallel_reduce()的樣子,關於使並行版本更快的建議? –

+0

那麼,Cory Nelson是對的,'parallel_reduce()'(可能是關鍵的)是瓶頸,你將不得不顯示那個代碼。我們這裏只能使用我們可以看到的代碼。 –

1

使用OpenMP構造總是有成本的,所以避免在循環內使用並行,在每次新線程執行之後可以啓動,而不是重新喚醒先前啓動的線程。

實際上,如果bodyContact.size()很小,並且do {}在步數很大的情況下很大,並且parallel_reduce非常快,只需幾個OpenMP pragma就很難具有可伸縮性。

#pragma omp parallel shared(totalVel) shared(bodyContact) 
{ 
    do { 
     totalVel = 0.; 
     #pragma omp for reduce(+:totalVel) 
     for (unsigned long i = 0; i < bodyContact.size(); i++) { 
      totalVel += bodyContact.at(i).bodyA()->parallel_reduce(); 
      totalVel += bodyContact.at(i).bodyB()->parallel_reduce(); 
     } 
    } while (totalVel >= 0.00001); 
}