我想要一个线程池,它可以让工作被分区或者#34; bucketed"以这种方式,任务将跨线程分布,但给定id的任务永远不会并行处理。
因此,例如,如果我在安排任务时有5个唯一ID和5个线程,我会期望id" 1"始终被分配给线程1,id" 2"始终被分配给线程2,id" 3"总是被分配给线程3等等。
如果有多个ID而不是线程,则每个线程可以分配多个id,例如,如果有10个ID和5个线程,则可以将线程1分配给id" 1"和" 5",线程2并被分配给id" 2"和" 6"等等
答案 0 :(得分:2)
我发现解决此问题的最简洁方法是使用ConcurrentExclusiveSchedulerPair,这是TPL的一部分,基本上以类似于读取器/写入器锁的方式工作,它公开了一个ExclusiveScheduler和一个ConcurrentScheduler 。 ConcurrentScheduler允许多个线程并发执行,ExclusiveScheduler一次只限于一个线程,当在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));
执行调度程序将确保永远不会为给定密钥同时处理任务。