简体   繁体   English

在 .NET 中优先安排任务

[英]Schedule tasks with priority in .NET

In .NET, I'd like to schedule a large number of Task s, eg via Task.Run(...) .在 .NET 中,我想安排大量的Task ,例如通过Task.Run(...) Some of the tasks are of low importance and should be delayed by the scheduler if higher priority tasks are available for execution.某些任务的重要性较低,如果有更高优先级的任务可供执行,则调度程序应将其延迟。

Is there a way to do this?有没有办法做到这一点? There seems to be no TaskScheduler in .NET that supports scheduling with any kind of priority. .NET 中似乎没有TaskScheduler支持任何优先级的调度。

The tasks are short-running and non-hierarchical.这些任务是短期运行的且不分等级的。 To be clear, this is entirely unrelated to the priority of the thread executing the tasks.需要明确的是,这与执行任务的线程的优先级完全无关。

QueuedTaskScheduler from ParallelExtensionsExtras seems to be what I am looking for, but that has been without maintenance for seven years, lacks documentation and most of the links related to it are broken - I'd rather not add a dependence on it.来自ParallelExtensionsExtras 的QueuedTaskScheduler似乎是我正在寻找的东西,但它已经七年没有维护了,缺乏文档,而且大部分与它相关的链接都已损坏 - 我宁愿不添加对它的依赖。

If you want to keep it simple, queue up an action instead of a task.如果您想保持简单,请将操作而不是任务排队。 Since we are queuing up asynchronous calls, the queue type is Func<Task> .由于我们正在排队异步调用,因此队列类型为Func<Task> Use two queues for the different priorities.对不同的优先级使用两个队列。

ConcurrentQueue<Func<Task>> _highPriorityQueue;
ConcurrentQueue<Func<Task>> _lowPriorityQueue;

Then create a worker proc to check both queues in priority order.然后创建一个工作进程以按优先级顺序检查两个队列。

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();
    }
}

Then start up some threads to work the queue:然后启动一些线程来处理队列:

var source = new CancellationTokenSource();
var threads = Enumerable.Range(0, numberOfThreads).Select( i =>
    Task.Run( () => WorkerProc(source.GetToken()) )
).ToList();

And to add to a queue:并添加到队列中:

_highPriorityQueue.Enqueue( () => Foo() );
_lowPriorityQueue.Enqueue( () => Bar() );

To shut down:去关机:

source.Cancel();
await Task.WhenAll( threads );

@John Wu gave a nice and simple answer for the case, when there are only 2 priorities. @John Wu 在只有 2 个优先事项的情况下,为这个案例提供了一个很好而简单的答案。

When there is need for more granular priorities, and possibly priority changes (like boosting a priority), an own priority based queue can be implemented.当需要更细粒度的优先级和可能的优先级更改(例如提高优先级)时,可以实现自己的基于优先级的队列。 For this some sorted or sortable list can be used, for example SortedList<TKey,TValue> .为此,可以使用一些已排序或可排序的列表,例如SortedList<TKey,TValue>

For the keys, I would suggest constructing something from the priority (as primary) and the scheduling time (as secondary).对于键,我建议从优先级(作为主要)和调度时间(作为次要)构建一些东西。 Be careful to make the keys unique.小心使键唯一。

Be very careful to make adding and removing tasks from the list thread safe (you will need to implement thread safety yourself, if the list does not provide it).要非常小心地从列表中添加和删除任务线程安全(如果列表没有提供,您将需要自己实现线程安全)。

Finally some iteration: the WorkerProc will look very similar, there will be only one task list (instead of the taks queue), adding and removing tasks instead of enqueing and dequeuing.最后一些迭代:WorkerProc 看起来非常相似,只有一个任务列表(而不是 taks 队列),添加和删除任务而不是入队和出队。 The tasks will sort themselves into the right position on adding by construction of the key.任务将通过构建密钥将自己分类到正确的位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM