2013-12-18 60 views
5

我正在使用別人的.NET 4開源平滑粒子流體動力學代碼,並試圖將其轉換爲Unity項目,您只能依靠它來達到.NET 2標準。不幸的是,代碼使用了Parallels類(這非常棒!),但他使用了一個比較模糊的過載。任何人都可以看到一個很好的方式來實現.NET 2中同樣的事情沒有巨大的性能打擊?將.NET 4線程轉換爲.NET 2

Parallel.For(
     0, 
     _numActiveParticles, 
     () => new Vector2[MAX_PARTICLES], 
     (i, state, accumulatedDelta) => calculateForce(_activeParticles[i], accumulatedDelta), 
     (accumulatedDelta) => 
     { 
      lock (_calculateForcesLock) 
      { 
       for (int i = _numActiveParticles - 1; i >= 0; i--) 
       { 
        int index = _activeParticles[i]; 
        _delta[index] += accumulatedDelta[index]/MULTIPLIER; 
       } 
      } 
     } 
    ); 

認爲這是代碼做什麼(非螺紋):

for (int i = 0; i < _numActiveParticles; i++) 
    { 
     Vector2[] temp = new Vector2[MAX_PARTICLES]; 
     temp = calculateForce(_activeParticles[i], temp); 


     for (int k = _numActiveParticles - 1; k >= 0; k--) 
     { 
      int index = _activeParticles[k]; 
      _delta[index] += temp[index]/MULTIPLIER; 
     } 
    } 
+2

您可能會發現這是很有幫助的http://stackoverflow.com/q/12386686/809009 –

+0

@OndrejJanacek由於這很有幫助,但我也不能100%確定Parallels版本在做什麼,所以我想確保我正確地翻譯它。 – PorcupineRending

+0

我不認爲你的理解是正確的。你甚至沒有在任何地方使用'temp'變量。閱讀此:http://msdn.microsoft.com/en-us/library/ff963547.aspx –

回答

1

你的第二個代碼是不正確的。我認爲正確的代碼是這樣的:

var accumulatedDelta= new Vector2[MAX_PARTICLES]; 

for(int i = 0; i < _numActiveParticles; ++i) 
{ 
    accumulatedDelta = calculateForce(_activeParticles[i], accumulatedDelta); 
} 

for (int i = _numActiveParticles - 1; i >= 0; i--) 
{ 
    int index = _activeParticles[i]; 
    _delta[index] += accumulatedDelta[index]/MULTIPLIER; 
} 

我不知道是什麼.net2有,哪些沒有。但你可以自己模擬Parallel.For。這個過載的Parallel.For

的解釋是這樣的:

第一個參數:啓動循環的指數

第二個參數:循環的結束索引

第三個參數:將創建任務的本地數據的委託。對於Parallel.For使用的每個線程(任務),此代理將被調用並返回localInit數據。

第四個參數:作爲for正文的代表。在首次執行主體委託時,此代理將檢索由預先委託(localInit)創建的數據。在每個後續循環中,主體代表可以更改localInit,然後將其返回到下一個主體執行。在上次執行主體委託時,localInit數據將傳遞給上一個委託。

最後一個參數:當任務完成後,每個任務將被調用的另一個委託。 localInit將傳遞給此代理。因爲這個委託可以被多個任務稱爲併發,所以你必須保護你的共享數據。

編輯:

ParallelFor一個版本可以是這樣的:

public static void ParallerFor<TLocal>(int startIndex, int endIndex, Func<TLocal> initData, Func<int, TLocal, TLocal> body, Action<TLocal> finalizer) 
    { 
     int numThreads = Environment.ProcessorCount; 
     int chunkOffset = ((endIndex - startIndex)/numThreads) + 1; 

     Task[] tasks = new Task[numThreads]; 

     Enumerable.Range(0, numThreads).ToList().ForEach(x => 
      { 
       int start = x * chunkOffset; 
       int end = ((x + 1) * chunkOffset); 
       end = end > endIndex ? endIndex : end; 

       tasks[x] = Task.Factory.StartNew(() => 
       { 
        TLocal init = initData(); 

        for(int i = start; i < end; ++i) 
        { 
         init = body(i, init); 
        } 

        finalizer(init); 
       }); 
      }); 

     Task.WhenAll(tasks).Wait(); 
    } 
+0

使用Task類來重新實現Parallel.For是一種心情。如果你有一個,你也有另一個(都是.NET 4以上)。 –

+0

@ Christian.K感謝您的提及。我不知道'.net 2'具有什麼樣的並行助手,但是用手動'線程'開始替換'task'是一件很簡單的工作。 – MRB

+0

您可以檢查msdn。它會告訴你。請注意,任務與線程不同(至少使用線程池而不是普通線程)。一般來說,重新實現TPL功能對於獲得正確和高效是非常重要的。大量關於互聯網的材料。 –