2011-03-16 49 views
0

我有一些代碼使用的Parallel.For做一些查詢和計數次數:在Parallel.For中刪除Interlocked.Add?

//...initialize _table with int values... 
int elements=60; 
int[] outerCounter=new int[elements]; 
Parallel.For(1, 2000, i0=> 
{ 
    int[] counter=new int[elements]; 
    int nextPos0=_table[10+i0]; 
    for(i1=i0+1; i1<1990; i1++){ 
    //...here are also some additionale calculations done... 

    int nextPos1=_table[nextPos0+i1]; 
    counter[nextPos1]++; 
    } 
    //synchronize 
    for(int i=0; i<elements;i++){ 
    Interlocked.Add(ref outerCounter[i], counter[i]); 
    } 
} 

這個版本是這樣快則連續計算。但我想找到一種不同的解決方案來計算髮生的事件,因爲Interocked.Add是一個瓶頸。 我正在調查Plinq是否是一個選項,但目前還沒有找到一種方法來計算數組中nextPos1元素的發生。

回答

0

我基本上會和Hans一樣推薦相同的東西,但我認爲提供一些代碼會很有用。以下是我大概會解決這個問題:

//...initialize _table with int values... 
int elements=60; 
List<int[]> outerCounter=new List<int[]>(); 
Parallel.For(1, 2000, i0=> 
{ 
    int[] counter; 
    lock(outerCounter) 
    { 
    if (outerCounter.Count == 0) 
     counter = new int[elements]; 
    else 
    { 
     counter = outerCounter[outerCounter.Count - 1]; 
     outerCounter.RemoveAt(outerCounter.Count - 1); 
    } 
    } 
    int nextPos0=_table[10+i0]; 
    for(i1=i0+1; i1<1990; i1++){ 
    //...here are also some additionale calculations done... 

    int nextPos1=_table[nextPos0+i1]; 
    counter[nextPos1]++; 
    } 
    lock (outerCounter) 
    outerCounter.Add(counter); 
}); 

int totalCounter = new int[elements]; 
Parallel.For(0, elements - 1, i => 
{ 
    foreach (int[] counter in outerCounter) 
    totalCounter[i] += counter[i]; 
}); 
+0

我做了一個測試,在雙核兩個版本都有關相同。在一個quad上,你的版本慢了5%。這種方法很有趣,應該根據情況加快。 – michael 2011-03-16 18:58:30

+0

我很好奇,如果你用SpinLocks替換Monitor鎖,性能如何改變四核。此外,您可能會考慮每次迭代進行更多的工作,例如將1-2000替換爲1到200,並且每次執行10次迭代。 – 2011-03-17 14:21:55

0

從我從代碼中得到的結果是,如果不鎖定outcounter [i],將無法正確執行此操作,因爲所有線程都將在outcounter中寫入所有值。

0

有點晚了這裏的聚會,但如果你只在計數器遞增值[]和outerCounter [],您可以使用並行的重載版本。對於()
不用創建元素的局部陣列中的每個循環中,可以創建一個本地的執行(並會在同一時間內僅操作於由一個線程) 。例如:

int elements=60; 
int[] outerCounter=new int[elements]; 

Parallel.For (1, 2000, 
() => new int[elements],      // Initialize the local value.  
    (i0, state, counter) => 
    { 
     int nextPos0=_table[10+i0]; 
     for(i1=i0+1; i1<1990; i1++) 
     { 
      //...here are also some additionale calculations done... 
      int nextPos1=_table[nextPos0+i1]; 
      counter[nextPos1]++; 
     } 
    } 

    counter =>         // Add the local value 
    { 
     for(int i=0; i<elements;i++) 
     { 
      Interlocked.Add(ref outerCounter[i], counter[i]); 
     } 
    } 
); 

我沒有測試過上面的代碼,但是這是它的主題。 這將大大減少你打電話Interlocked.Add()

欲瞭解更多信息,倍量,這個網站是非常好的: http://www.albahari.com/threading/part5.aspx