在.NET中,我想安排大量的Task
,例如通过Task.Run(...)
。一些任务的重要性不高,如果可以执行更高优先级的任务,则应由调度程序延迟。
有没有办法做到这一点? .NET中似乎没有TaskScheduler
支持任何优先级的调度。
这些任务是短期运行的,不是分层的。需要明确的是,这与执行任务的线程的优先级完全无关。
QueuedTaskScheduler
中的[ParallelExtensionsExtras]似乎是我想要的,但这已经有七年没有维护了,缺少文档,并且大多数与它相关的链接都被破坏了-我宁愿不添加依赖它。
如果要保持简单,请排队一个动作而不是一个任务。由于我们正在排队异步调用,因此队列类型为Func<Task>
。将两个队列用于不同的优先级。
ConcurrentQueue<Func<Task>> _highPriorityQueue;
ConcurrentQueue<Func<Task>> _lowPriorityQueue;
然后创建一个工作进程以按优先级顺序检查两个队列。
async Task WorkerProc(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
Func<Task> action;
if (_highPriorityQueue.TryDequeue(out action))
{
await action();
continue;
}
if (_lowPriorityQueue.TryDequeue(out action))
{
await action();
continue;
}
await Task.Yield();
}
}
然后启动一些线程来处理队列:
var source = new CancellationTokenSource();
var threads = Enumerable.Range(0, numberOfThreads).Select( i =>
Task.Run( () => WorkerProc(source.GetToken()) )
).ToList();
并添加到队列中:
_highPriorityQueue.Enqueue( () => Foo() );
_lowPriorityQueue.Enqueue( () => Bar() );
要关闭:
source.Cancel();
await Task.WhenAll( threads );
@@吴Wu在只有两个优先事项的情况下给出了一个很好而简单的答案。
当需要更精细的优先级,并且可能需要更改优先级(例如提高优先级)时,可以实现自己的基于优先级的队列。为此,可以使用一些已排序或可排序的列表,例如SortedList<TKey,TValue>
。
对于键,我建议根据优先级(作为主要)和调度时间(作为次要)构造一些东西。请注意使键唯一。
请特别注意使从列表线程中添加和删除任务安全(如果列表未提供,则您需要自己实现线程安全)。
最后进行一些迭代:WorkerProc看起来非常相似,只有一个任务列表(而不是taks队列),添加和删除任务而不是入队和出队。通过构造键,任务将自己分类到正确的位置。