2015-02-09 51 views
3

爲線程完成一個隊列線路的最佳方式是什麼,以便我只能擁有最大數量的線程,並且如果我已經有很多代碼在等待空閒槽之前繼續..在繼續執行代碼之前等待空閒的線程槽號

我的意思僞codeish例子,我確信這可以以更好的方式來完成...

(請檢查下面的附加要求)

private int _MaxThreads = 10; 
private int _CurrentThreads = 0; 

public void main(string[] args) 
{ 
    List<object> listWithLotsOfItems = FillWithManyThings(); 

    while(listWithLotsOfItems.Count> 0) 
    { 
     // get next item that needs to be worked on 
     var item = listWithLotsOfItems[0]; 
     listWithLotsOfItems.RemoveAt(0); 

     // IMPORTANT!, more items can be added as we go. 
     listWithLotsOfItems.AddRange(AddMoreItemsToBeProcessed()); 

     // wait for free thread slot 
     while (_CurrentThreads >= _MaxThreads) 
      Thread.Sleep(100); 

     Interlocked.Increment(ref _CurrentThreads); // risk of letting more than one thread through here... 
     Thread t = new Thread(new ParameterizedThreadStart(WorkerThread(item)); 
     t.Start(); 
    } 
} 

public void WorkerThread(object bigheavyObject) 
{ 
    // do heavy work here 
    Interlocked.Decrement(ref _CurrentThreads); 
} 

看着Sempahore但似乎需要在t內運行他在線程創建之前並不在外線。在這個例子中,Semaphore在線程內部被創建後用於暫停它,在我的情況下,可能有超過10萬個線程需要在作業完成之前運行,所以我寧願在插槽可用之前創建線程。 (link to semaphore example

在實際應用中,數據可以被添加到項目列表的程序進行所以Parallel.ForEach將沒有真正的工作是(我在SSIS這樣的腳本組件包發送數據到一個非常慢的WCF)。

SSIS具有.NET 4.0

+0

您是否嘗試過使用Semaphore和SemaphoreSlim? https://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim%28v=vs.110%29.aspx – 2015-02-09 15:40:56

+0

@ Benji_9989是的,請看我添加的評論。 – JensB 2015-02-09 15:42:56

+0

傾向於使用類似['Parallel.ForEach']的構造(https://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach%28v=vs.110%29.aspx )使用MaxDegreeOfParallelism選項,而不是手動創建和管理線程(如果可能的話)。 – 2015-02-09 15:46:07

回答

0

您是否使用等待句柄考慮?請參閱this

此外,您還可以使用Parallel.Foreach爲您管理線程創建。

希望它幫助;)

2

要做到這一點,最簡單的方法是使用的Parallel.ForEach()過載,它允許您選擇MaxDegreeOfParallelism

下面是一個示例程序:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Demo 
{ 
    public static class Program 
    { 
     private static void Main() 
     { 
      List<int> items = Enumerable.Range(1, 100).ToList(); 

      Parallel.ForEach(items, new ParallelOptions {MaxDegreeOfParallelism = 5}, process); 
     } 

     private static void process(int item) 
     { 
      Console.WriteLine("Processing " + item); 
      Thread.Sleep(2000); 
     } 
    } 
} 

如果你運行它,你會發現它非常快處理5個元素,然後有被處理的元素的一個數據塊之前的延遲(由Thread.Sleep(2000)) 。這是因爲在這個示例代碼中,不能超過5個線程一次執行。

請注意,如果MaxDegreeOfParallelism超過線程池的最小線程值,則可能需要一段時間才能啓動所有線程。

原因是Parallel.ForEach()使用線程池線程 - 並且默認情況下,線程池保持可用的線程數量是一定的。創建超出此限制的線程時,會在每個新線程池線程創建之間引入延遲。

您可以使用ThreadPool.SetMinThreads()將線程池線程的最小數量設置爲更高的值,但我不建議這樣做。

但是,如果你想這樣做,這裏的這臺最小線程數到20的例子:

ThreadPool.GetMinThreads(out dummy, out ioThreads); 
ThreadPool.SetMinThreads(20, ioThreads); 

如果你這樣做,然後用MaxDegreeOfParallelism = 20運行前面的代碼,你會看到,初始線程創建時不再有任何延遲。

+0

如何處理'items'列表在執行過程中獲取更多項目?我可以在一段時間內將整個Parallel.ForEach封裝起來,在最壞的情況下,它會循環並重新開始一個新的...也許這就是最好的方法。 – JensB 2015-02-09 16:12:47

+0

你最後的陳述是不正確的。 'Parallel.Foreach'將愉快地請求比處理器更多的線程。然而,它仍然有一個「技巧」,「Parallel.Foreach'只會在第一次穿過主體時使用非常少的線程,每個循環都會添加更多線程,直到達到最大值。最後一段應該說「注意MaxDegreeOfParallelism設置是MAXIMUM值;'Parallel.Foreach'可能使用的線程少於您在其」預熱「階段開始時在最大值中指定的線程數。 – 2015-02-09 16:13:04

+0

我在循環內放置了一個斷點,查看了工作線程的數量。 [第一擊](http://i.stack.imgur.com/hknEI.png)主線程+2個工作線程(3個線程正在運行),[第二擊](http://i.stack.imgur.com/ VjNg4.png)主線程+ 3個工作線程(4個線程正在運行),[第三次命中](http://i.stack.imgur.com/Hurb5.png)主線程+4個工作線程(5個線程正在運行)。在那之後,它停留在5個線程上。 – 2015-02-09 16:22:47

3

所以,讓我首先說,你要做的只是給你一個非常具體的安排性能的小幅提高。嘗試調整線程分配級別可能需要很多工作,因此在繼續之前請確保您有一個非常好的理由。

現在,首先,如果你想簡單地排隊工作,你可以把它放在.NET線程池中。它只會將線程分配給最大配置,並且任何不適合這些線程的工作(如果所有線程都處於繁忙狀態)將排隊等待線程變爲可用狀態。

要做到這一點,最簡單的方法是調用:

Task.Factory.StartNew(() => { /* Your code */}); 

這將創建一個TPL任務,並安排其在默認任務調度,這應該反過來任務分配給線程池中運行。

如果您需要等待這些任務,然後再繼續完成,你可以將它們添加到集合,然後使用Task.WaitAll(...)

var tasks = new List<Task>(); 

tasks.Add(Task.Factory.StartNew(() => { /* Your code */})); 

// Before leaving the script. 
Task.WaitAll(tasks); 

但是,如果你需要去深入和控制這些調度任務,您可以查看創建支持有限併發性的自定義任務計劃程序。 This MSDN article有關它的更多細節並建議可能的實現,但這不是一項簡單的任務。

相關問題