2017-06-01 76 views
-1

我試圖讓我的代碼的一部分並行運行,我試圖在C#中使用ThreadPool,以避免任何頭痛,但似乎我要求太多的池,我的代碼實際上它運行得更慢!C#並行處理選項

下面的代碼解釋了我想要做的事情,我有大量的音頻樣本(取決於緩衝區大小從512-> 4096的任何地方),需要插入,傳播和讀取節點(從n = 4到n = 16)。這必須以樣本爲基礎進行,因此我唯一的優化選擇是對網絡中存在的每個節點採用插入/傳播/讀取並具有並行操作的部分。該操作在每個遊戲幀中調用一次,並且在遊戲的整個生命週期中都需要。看一下剖析器,散射操作需要大量的時間,所以它是一個很好的候選者(我已經完成了傳統的優化)。目前,我有一個線程池工作人員爲一個工作項目中的所有節點完成工作,只是爲了啓動和運行,但稍後可以拆分工作。

我認爲下面的代碼的問題是插入到線程池的工作項的頻率,我也讀過某些地方,線程需要一段時間才能旋轉起來,所以如果線程池創建更多,它不neccserally幫助。有沒有人有任何其他並行處理方法的建議,或可以發現我的線程池實施的任何錯誤?

public void propagateNetwork() { 

    int numSampsToConsume = Mathf.min(inSamples.Count,buffersize); 

    for (int i = 0; i < numSampsToConsume; i++) { 
     outVal = 0.0f; 
     inVal = inSamples.Dequeue() * networkInScale; 

     directDelay.write (inVal); 
     directVal = directDelay.read(); 
     directVal *= directAtt; 

     for (j = 0; j < network.Count; j++) { 
      outVal += network [j].getOutgoing(); 
      network [j].inputIncoming (inVal); 
     } 

     ThreadPool.QueueUserWorkItem (scatteringThreadPoolWrapper); 
     scatteringThreadDone.WaitOne(); 

     outVal += directVal; 
     outSamples.Enqueue (outVal); 
    } 
} 

public void scatteringThreadPoolWrapper(object threadConext) { 
    doScatteringForNodeRange (0, network.Count); 
} 

public void doScatteringForNodeRange(int min,int max) { 
    for (int i = min; i < max; i++) { 
     network[i].doScattering (doLateReflections); 
    } 
    scatteringThreadDone.Set(); 
} 
+1

如果你排隊然後馬上等待,那不就是刪除了嗎?你不應該排隊所有的工作項目,然後等待他們在另一個循環完成?也許考慮用'Parallel.for'替代你的外部? – NetMage

+0

也許我誤解了線程池的功能,但我認爲我分配給它的每個任務可能都在不同的線程上。因此總體來說它會更快完成?我知道在示例代碼中,我還沒有將工作分解,這只是一個測試,看它是否可行。我需要等待,因爲每個樣本必須在完成傳播之前完成傳播,出於同樣的原因,並行是不可能的。 – Rampartisan

+0

每個任務可能位於不同的線程上,但是如果您將任務發送到另一個線程,然後等待在主線程上運行另一個任務之前取回答案,那麼當然您會更慢。您仍然一次只運行一個線程,但是您添加了創建線程和跨線程通信的開銷。 – NetMage

回答

0

也許使用Parallel.for會工作嗎?我在每個循環迭代中都創建了一些本地變量,但我不知道這些操作都在做什麼,以及如果這些操作可能會導致問題(如果並行運行)。

public void propagateNetwork() { 
    int numSampsToConsume = Mathf.min(inSamples.Count,buffersize); 

    Parallel.for(0, numSampsToConsume, i => { 
     var outVal = 0.0f; 
     var inVal = inSamples.Dequeue() * networkInScale; 

     directDelay.write (inVal); 
     var directVal = directDelay.read(); 
     directVal *= directAtt; 

     Parallel.for(0, network.Count, j => { 
      outVal += network [j].getOutgoing(); 
      network [j].inputIncoming (inVal); 
     }); 

     doScatteringForNodeRange (0, network.Count); 

     outVal += directVal; 
     outSamples.Enqueue (outVal); 
    }); 
} 
+0

剛剛實現了最內層的並行,它仍然需要比正常的循環更長的循環!不同於線程池會嘗試在池中重複使用儘可能多的線程,並且只在需要時才創建新線程嗎?我認爲我的主要問題是旋轉新線程花費的時間太長(如果這是平行進行的) 最外面的循環不能平行,因爲每個樣本必須按順序傳播。 – Rampartisan

+0

並行操作的嵌套可能會導致速度下降,但它仍然是在調用點(例如,調制解調器)的「同步」操作。doScatteringForNodeRange在內部循環完成之前不會運行),這意味着每個外部循環都在管理並行狀態,產生其他並行任務並暫停。理想情況下,你需要一個循環來完成一切,如下所示:1.查看是否可以擴展內部循環以成爲主要驅動程序,以及2.避免任何共享狀態訪問。 – Clint

+0

通過並行操作的嵌套你是否意味着在這個asnwer中的2個並行?因爲正如我之前提到的,我不能將外部看作平行的,因此並沒有像這樣實施。所有音頻樣本都必須按順序處理,只有內部操作是並行性的候選對象。 但是你關於交換內部和外部循環的觀點很有趣,我會考慮一下,如果這是可能的! – Rampartisan