2017-04-07 1 views
-1

私はしばらくの間、単純なカスタムスレッドプールを見つけようとしていましたが、見つからないので、素早く貧しい人のスレッドプールを作成しました。C#。カスタムスレッドプール用の.NETクラス

質問

  1. すでにこれを行うことができます任意の.NETクラスはありますか? (これを見つけるために何度も試みた後、それを見つけることができず、これよりもはるかに複雑なブログ投稿のカスタム実装のみ!)。

  2. スレッドプールでタスクをポーリングしたり、タスクを開始したりしてスレッドを消費する方が良いですか? < 1kタスク/日。

    [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()); 
        } 
    

    、正しい(または十分に正しい)である。この出力を得る

    :これはケストレル

コード

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}"); 
     } 
    } 
} 

とテストにAspNetCoreサイトとして実行されています

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

あなたは0を見ることができますには、いくつかのタスクスケジューラがあります。具体的には、WorkStealingTaskScheduler

私はそれをテストしたことを覚えています。管理された世界では、少なくとも安全でないコードはなく、.NET独自のスレッドプールと比較していません。 .NETの在庫スレッドプールには多くの最適化がありますが、私が覚えていることは、待機する前に作業項目を処理した後、積極的に作業項目を回転させることです。

明るい側では、非常に近くになることができますが、ThreadPoolのことをエミュレートするのはすばらしいことです。つまり、そうしたいのであれば。私がでなく、がデフォルトのスレッドプールを使用したい理由の1つは、minの後にスレッドをゆっくり作成するというポリシーのためです。単にminを増やすだけです。スレッドは通常十分です。

TPL を使用していない限り、独自のタスクスケジューラを提供することはできますが、通常はレガシーコードでは在庫スレッドプールインターフェイスがないためカスタムスレッドプールを拾いません。残念ながら、ThreadPoolが静的​​クラスであるという事実は、他のスレッドプールの使用をさらに嫌っています。

+0

私はデフォルトのThreadpoolをオーバーライドするのではなく、別のスレッドプールを探しています。私は作業できるようにして、一度に実行できるスレッド数を指定します。 –

+1

私はそれを理解しています、あなたは私の最初の段落を読んだのですか? 'WorkStealingTaskScheduler'はおそらく、マイクロソフト自身がマネージコードでスレッドプールの実装にもっとも近いものです。同じプロジェクトの 'LimitedConcurrencyLevelTask​​Scheduler'を見てください。 – acelent

関連する問題