この問題を解決するために私が見つけた最もクリーンな方法は、 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));
実行スケジューラは、タスクが決して特定のキーに対して同時に処理されないようにします。
SmartThreadPool - https://smartthreadpool.codeplex.com/とその作業項目グループ機能 – Jan