Расписание задач с приоритетом в. NET - PullRequest
1 голос
/ 22 февраля 2020

In. NET, я бы хотел запланировать большое количество Task с, например, через Task.Run(...). Некоторые задачи имеют низкое значение и должны быть отложены планировщиком, если задачи с более высоким приоритетом доступны для выполнения.

Есть ли способ сделать это? Кажется, нет TaskScheduler in. NET, который поддерживает планирование с любым видом приоритета.

Задачи являются краткосрочными и неиерархическими. Чтобы было ясно, это совершенно не связано с приоритетом потока, выполняющего задачи.

QueuedTaskScheduler из ParallelExtensionsExtras , кажется, то, что я ищу, но это было без обслуживания в течение семи лет не хватает документации, и большинство связанных с ней ссылок не работает - я бы предпочел не добавлять в нее зависимость.

Ответы [ 2 ]

2 голосов
/ 22 февраля 2020

Если вы хотите сохранить простоту, поставьте в очередь действие вместо задачи. Поскольку мы ставим в очередь асинхронные вызовы, тип очереди - Func<Task>. Используйте две очереди для разных приоритетов.

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

Затем создайте рабочего профи c, чтобы проверить обе очереди в порядке приоритетов.

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 голосов
/ 24 февраля 2020

@ Джон Ву дал хороший и простой ответ для случая, когда есть только два приоритета. может быть реализована собственная очередь на основе приоритетов. Для этого можно использовать отсортированный или сортируемый список, например SortedList<TKey,TValue>.

Для ключей я бы предложил построить что-то из приоритета (как первичного) и времени планирования (как вторичного). Будьте осторожны, чтобы ключи были уникальными.

Будьте очень осторожны, чтобы сделать добавление и удаление задач из потока списка безопасным (вам нужно будет реализовать безопасность потоков самостоятельно, если список этого не обеспечивает).

Наконец, некоторая итерация: WorkerPro c будет выглядеть очень похоже, будет только один список задач (вместо очереди taks), добавление и удаление задач вместо постановки в очередь и выгрузки из очереди. Задачи сортируются в правильную позицию при добавлении по построению ключа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...