。NET中具有优先级的计划任务

问题描述 投票:1回答:2

在.NET中,我想安排大量的Task,例如通过Task.Run(...)。一些任务的重要性不高,如果可以执行更高优先级的任务,则应由调度程序延迟。

有没有办法做到这一点? .NET中似乎没有TaskScheduler支持任何优先级的调度。

这些任务是短期运行的,不是分层的。需要明确的是,这与执行任务的线程的优先级完全无关。

QueuedTaskScheduler中的[ParallelExtensionsExtras]似乎是我想要的,但这已经有七年没有维护了,缺少文档,并且大多数与它相关的链接都被破坏了-我宁愿不添加依赖它。

c# .net task-parallel-library
2个回答
3
投票

如果要保持简单,请排队一个动作而不是一个任务。由于我们正在排队异步调用,因此队列类型为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 );

0
投票

@@吴Wu在只有两个优先事项的情况下给出了一个很好而简单的答案。

当需要更精细的优先级,并且可能需要更改优先级(例如提高优先级)时,可以实现自己的基于优先级的队列。为此,可以使用一些已排序或可排序的列表,例如SortedList<TKey,TValue>

对于键,我建议根据优先级(作为主要)和调度时间(作为次要)构造一些东西。请注意使键唯一。

请特别注意使从列表线程中添加和删除任务安全(如果列表未提供,则您需要自己实现线程安全)。

最后进行一些迭代:WorkerProc看起来非常相似,只有一个任务列表(而不是taks队列),添加和删除任务而不是入队和出队。通过构造键,任务将自己分类到正确的位置。

© www.soinside.com 2019 - 2024. All rights reserved.