2017-04-07 79 views
-1

我一直在試圖找到一個簡單的自定義線程池一段時間,並找不到一個,所以寫了一個快速窮人的線程池。C#。是否有自定義線程池的.NET類

問題

  1. 有任何.NET類已經可以做到這一點? (無數次試圖找到它之後找不到它,只有博客文章中的自定義實現比這更復雜!)。

  2. 更好地消耗線程與輪詢或啓動線程池上的操作時和當任務進來? <每天1k任務。這將是對紅隼

    運行的AspNetCore網站

代碼

public class WorkerQueue : IWorkerQueue 
{ 
    private readonly Queue<WorkItem> _items = new Queue<WorkItem>(); 

    private int _max = 2; // Would be configurable 
    private int _running; 
    private Stopwatch _stopwatch; 

    public WorkerQueue() 
    { 
     _stopwatch = new Stopwatch(); 
     _stopwatch.Start(); 
    } 

    public void Add(WorkItem workItem) 
    { 
     lock (_items) 
     { 
      if (_running >= _max) 
      { 
       Log($"Queuing Item {workItem.Name} - _running >= _max"); 
       _items.Enqueue(workItem); 
       return; 
      } 

      _running++; 

      Log($"Running Item {workItem.Name} - _running = {_running}"); 
      var task = Task.Run(workItem.Action); 

      task.ContinueWith(t => OnActionCompleted(workItem.Name)); 
     } 
    } 

    private void Log(string msg) 
    { 
     Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} @ {_stopwatch.ElapsedMilliseconds}ms : {msg}"); 
    } 

    private void OnActionCompleted(string obj) 
    { 
     Log($"OnActionCompleted {obj}"); 
     WorkItem item = null; 

     lock (_items) 
     { 
      if (_items.Count > 0) 
       item = _items.Dequeue(); 
      else 
       _running--; 
     } 

     if (item != null) 
     { 
      // Potential Stack Overflow if big queue builds up? 
      // Probably should be a while loop rather than recursion? 
      Log($"Running Next Item {item.Name}"); 
      item.Action(); 
      OnActionCompleted(item.Name); 
     } 
     else 
     { 
      Log($"Sleeping. _running = {_running}"); 
     } 
    } 
} 

和測試:

[Fact] 
    public void Test() 
    { 
     var sb = new StringBuilder(); 
     Console.SetOut(new StringWriter(sb)); 

     var resetEvent = new ManualResetEventSlim(); 

     AddItem("A", 100); 
     AddItem("B", 250); 
     AddItem("C", 100); 
     AddItem("D", 100); 
     AddItem("E", 100); 
     AddItem("G", 100,() => 
     { 
      Thread.Sleep(250); 
      resetEvent.Set(); 
     }); 

     resetEvent.Wait(2500); 

     Assert.True(resetEvent.IsSet); 

     _output.WriteLine(""); 
     _output.WriteLine("------------------ Test Finished ------------------"); 
     _output.WriteLine("------------------ Console Out ------------------"); 
     _output.WriteLine(""); 
     _output.WriteLine(sb.ToString()); 
    } 

而得到這個輸出是正確的(或相當正確的)

Thread 14 @ 8ms : Running Item A - _running = 1 
Thread 14 @ 8ms : Running Item B - _running = 2 
Thread 14 @ 8ms : Queuing Item C - _running >= _max 
Thread 14 @ 8ms : Queuing Item D - _running >= _max 
Thread 14 @ 8ms : Queuing Item E - _running >= _max 
Thread 14 @ 8ms : Queuing Item G - _running >= _max 
Thread 21 @ 110ms : OnActionCompleted A 
Thread 21 @ 110ms : Running Next Item C 
Thread 21 @ 211ms : OnActionCompleted C 
Thread 21 @ 211ms : Running Next Item D 
Thread 20 @ 260ms : OnActionCompleted B 
Thread 20 @ 260ms : Running Next Item E 
Thread 21 @ 311ms : OnActionCompleted D 
Thread 21 @ 311ms : Running Next Item G 
Thread 20 @ 360ms : OnActionCompleted E 
Thread 20 @ 360ms : Sleeping. _running = 1 
Thread 21 @ 662ms : OnActionCompleted G 
Thread 21 @ 662ms : Sleeping. _running = 0 
+2

我投票結束這個問題作爲題外話,因爲它應該屬於http://codereview.stackexchange.com網站 –

+0

@SergeyBerezovskiy改變了問題,問是否已經有一些可用的.NET框架已經存在 –

+0

任務是.NETCore中的新線程,它通過線程池進行管理。 –

回答

1

你可以看看parallel extensions extras project,它有幾個任務調度器。具體而言,WorkStealingTaskScheduler

我記得經過測試,託管世界裏沒有任何東西與.NET自己的線程池相比,至少沒有不安全的代碼。 .NET的股票線程池在引擎蓋下有很多優化,我清楚地記得,在等待之前處理一個工作項目後,工作項目正在積極旋轉。

在光明的一面,你可以非常接近它,但模擬ThreadPool做的是一個相當偉大的事情。也就是說,如果你想這樣做。我希望而不是使用默認線程池的其中一個原因是由於其關於在最小化後慢速創建線程的策略。線程,但只需增加分鐘。線程通常足夠好。

的事情是,除非你正在使用TPL 您可以提供自己的任務調度,通常不出意外,尤其是遺留代碼,是要拿起你的自定義線程池,因爲沒有庫存線程池接口。不幸的是,ThreadPool是一個靜態類,這進一步阻礙了其他線程池的使用。

+0

我不想重寫默認的線程池,而是一個單獨的線程池,我可以工作,並指定一次可以運行多少個線程池。 –

+1

我明白了,你看了我的第一段嗎? WorkStealingTaskScheduler可能是微軟自己託管的代碼中最接近線程池實現的東西。但請參閱同一項目中的'LimitedConcurrencyLevelTask​​Scheduler'。 – acelent