2016-05-31 10 views
0

私は、タスクがスレッド間で分散されるが、特定のIDのタスクは決して並列処理されないように、作業をパーティション化または「バケツ」することができるスレッドプールを希望します。C#でパーティション化されたスレッドプールを作成する最もクリーンな方法は何ですか?

たとえば、タスクをスケジュールするときに5つの一意のIDと5つのスレッドがある場合、id "1"のタスクは常にスレッド1に割り当てられ、id "2"のタスクは常にスレッドに割り当てられます2の場合、スレッド3などに常にid "3"のタスクが割り当てられます。

スレッドよりもidsが多い場合は、各スレッドに複数のidを割り当てることができますスレッド1はid "1"と "5"、スレッド2に割り当てられ、id "2"と "6"などに割り当てられます。

+0

SmartThreadPool - https://smartthreadpool.codeplex.com/とその作業項目グループ機能 – Jan

答えて

2

この問題を解決するために私が見つけた最もクリーンな方法は、 a ConcurrentExclusiveSchedulerPair、これはTPLの一部であり、基本的にはリーダライタロックと同様に、ExclusiveSchedulerとConcurrentSchedulerを公開します。 ConcurrentSchedulerは複数のスレッドを同時に実行でき、ExclusiveSchedulerは一度に1つのスレッドのみに制限され、ExclusiveSchedulerでスレッドが実行されている間はスレッドはConcurrentSchedulerで実行できません。

シャーディングアルゴリズムを使用してユニークIDに割り当てられたExclusiveSchedulerオブジェクトのプールを維持することで、パーティションスケジューラーを実装できます。

public class TaskSchedulerPool 
    { 
     private readonly List<Lazy<TaskScheduler>> _taskSchedulers; 

     public TaskSchedulerPool(int maxSize) 
     { 
      _taskSchedulers = Enumerable.Range(1, maxSize) 
       .Select(
        _ => new Lazy<TaskScheduler>(() => new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler)) 
       .ToList(); 
     } 

     public TaskScheduler GetTaskScheduler(object o) 
     { 
      var partition = Math.Abs(o.GetHashCode())%_taskSchedulers.Count; 
      return _taskSchedulers[partition].Value; 
     } 

    } 

タスクを作成しているときに、特定のIDのスケジューラを取得し、それを使用してタスクをスケジュールできます。

Task.Factory.StartNew(() => Console.WriteLine("Doing work here"), cancel.Token, TaskCreationOptions.None, pool.GetTaskScheduler(key)); 

実行スケジューラは、タスクが決して特定のキーに対して同時に処理されないようにします。

関連する問題