2016-07-25 69 views
2

我正在寫一個相當簡單的Raytracer,並且由於該程序是單線程的,所以我遇到了運行時限制。我一直通過google發現的結果都是通過兩個或三個任務來處理這種類型的問題。創建大量的任務/線程並等待它們全部完成

class Program 
{ 
    static void Main(string[] args) 
    { 
     var taskList = new List<Task>(); 

     taskList.Add(Task.Factory.StartNew(() => doStuff())); 
     taskList.Add(Task.Factory.StartNew(() => doStuff())); 
     taskList.Add(Task.Factory.StartNew(() => doStuff())); 

     Task.WaitAll(taskList); 

     Console.WriteLine("All threads complete"); 
    } 

    static void doStuff() 
    { 
     //do stuff here 
    } 
} 

我正在看atleast 10,000個人的線程,如果天真地執行。上面的解決方案看起來不像這種情況下的最佳解決方案。有沒有支持這個標準庫的一部分,或者是否有一個Nuget包具有類似的實現?它可能也只是我的愚蠢,並且在一個List中> 10,000個線程根本不是問題。那麼問題就出現在截止時間。在某些情況下,我需要12500000個任務/線程,對於列表,我相當肯定太多了。

下面大概是我將如何創建一個新的線程/任務,因爲它現在。

for (var x = 0; x < image.Width; x++) { 
    for (var y = 0; y < image.Height; y++) { 
     var coordinates = new Vector3(x, y, 0); 
     var task = new Task(() => { 
      RenderSinglePixel(coordinates); 
     }); 
    } 
} 
+2

一般的整體速度,具有比處理器內核多個線程的計算密集型任務是壞的。 –

+0

這就是我的想法。處理我的情況的正確方法是什麼? – Herbstein

+0

我會嘗試添加一個示例。 –

回答

2

如果您有想要使用多線程來處理值的列表(或其他IEnumerable<T>),你可以使用.AsParallel()這樣做。

這會智能地限制同時生成的線程數,具體取決於處理器的功能。但是,請注意,每個項目的工作量相對較大時,應僅使用此項。

下面是一個例子:

using System; 
using System.Linq; 
using System.Threading; 

namespace Demo 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var numbersToProcess = Enumerable.Range(1, 1000); 

      numbersToProcess.AsParallel().ForAll(doStuff); 
     } 

     static void doStuff(int value) 
     { 
      Console.WriteLine("Thread {0} is processing {1}", Thread.CurrentThread.ManagedThreadId, value); 
      Thread.Sleep(250); // Simulate compute-bound task. 
     } 
    } 
} 

另一種方法是爲每個方法調用創建任務,但它變得更難以知道當所有的線程都完成,除非你存儲的任務,以等待他們完成(但線程池的使用將確保線程的數量沒有得到太大):

using System; 
using System.Linq; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Demo 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var numbersToProcess = Enumerable.Range(1, 1000); 

      foreach (int number in numbersToProcess) 
      { 
       int n = number; 
       Task.Run(() => doStuff(n)); 
      } 

      Console.ReadLine(); 
     } 

     static void doStuff(int value) 
     { 
      Console.WriteLine("Thread {0} is processing {1}", Thread.CurrentThread.ManagedThreadId, value); 
      Thread.Sleep(250); // Simulate compute-bound task. 
     } 
    } 
} 

注意這種方法並運行的線程的數量失控的風險正在創建,我f每次撥打doStuff()需要很長時間。如果將Thread.Sleep(250)更改爲Thread.Sleep(100000)並運行該程序,則會看到創建了大量線程。

但是你最好的選擇是使用the DataFlow TPL

+0

我想我可以創建一個應該被處理的座標數組,但這看起來非常低效。是否沒有像這樣的ThreadPool方法? – Herbstein

+0

@Herbstein您可以按照我的第二個示例使用'Tasks',但正如我指出的那樣,知道最後一項任務何時完成會更加尷尬。但聽起來你可能會想看看DataFlow TPL--有一個很大的學習曲線,但它很可能是最適合你想要的。 –

+0

感謝您的幫助!我現在可能會實現一個只有「任務」的版本,然後在我有更多時間的情況下查看DataFlow TPL。再次感謝。 – Herbstein

1

使用並行循環來處理小物體模式。 https://msdn.microsoft.com/en-us/library/dd560853(v=vs.110).aspx

當的Parallel.For循環有一個小的身體,它可能比同等順序循環執行更慢,比如在C#環路和在Visual Basic循環。性能降低是由於分區數據所涉及的開銷以及在每次循環迭代中調用委託的成本造成的。爲了解決這種情況,Partitioner類提供了Partitioner.Create方法,該方法使您可以爲委託體提供一個順序循環,以便每個分區僅調用一次委託,而不是每次迭代一次。

小型機構模式的並行循環模式實質上對可枚舉類進行分區,並根據處理器的數量在多個線程中執行循環。每個線程都有自己的分區組。

在這種情況下,此模式比正常的並行循環更好(性能更好),因爲它避免了創建比所需更多線程的開銷。

比CPU內核使用線程的詳細只會減慢處理

+1

請解釋這是如何與線程相關的。 –

+0

鏈接只有答案是皺眉,如果鏈接永遠不死的答案不再有任何價值。請在報價塊中包含您答案中鏈接的相關信息。 – Phaeze

+0

@Devlin對於小型體的並行循環模式實質上對可枚舉進行分區,並根據處理器的數量在多個線程中執行循環。每個線程都將有自己的分區組進行工作。 –