Проблемы планирования / запуска задачи на пользовательском TaskScheduler, который завершит выполнение на указанном планировщике - PullRequest
0 голосов
/ 09 марта 2020

Работа, которую я пытаюсь запланировать, использует ключевое слово await, поэтому сама работа имеет тип async Task.

Я не могу использовать Task.Factory.StartNew, даже когда я передаю свой планировщик, потому что он будет считать задачу выполненной, когда достигнет первого ожидания работы, заставит ее покинуть планировщик и продолжит работу по умолчанию.

Я не могу использовать var a = new Task(DoWork....); a.Start(myScheduler), потому что я Я бы использовал метод async void, и мы знаем, что с этим связано.

Я не могу использовать Task.Run(), потому что он не позволяет вам изменить планировщик, на котором будет выполняться задача. Запланировано для запуска.

Если я не могу использовать что-либо из этого, как я достигну своей цели, которая заключается в планировании моей асинхронной работы c Работа, которая должна завершить выполнение в планировщике, который был первоначально запущен на

1 Ответ

3 голосов
/ 09 марта 2020

Во-первых, имейте в виду, что TaskScheduler относится только к выполнению задач. Таким образом, при использовании делегата async, TaskScheduler будет использоваться только между await точками; когда код async (асинхронно) ожидает в await, то в этом планировщике нет кода «в». Для некоторых планировщиков это не проблема, но это проблема с планировщиками, такими как ConcurrentExclusiveSchedulerPair, потому что код не находится "в" планировщике во время await.

Если ваш TaskScheduler будет работать Как и ожидалось с кодом async, вы можете создать задачу, выполняющуюся на нем, вызвав Task.Factory.StartNew и передав свой TaskScheduler. Это вернет Task<Task> или Task<Task<T>>, поскольку StartNew не понимает async код; Вы можете вызвать Unwrap() для этого значения, чтобы получить «нормальный» асинхронный Task / Task<T>.

Лично я предпочитаю создать собственный экземпляр TaskFactory с вашим собственным TaskScheduler (и другими опций), а затем назовите это StartNew с Unwrap. Например:

var factory = new TaskFactory(CancellationToken.None, TaskCreationOptions.DenyChildAttach,
    TaskContinuationOptions.DenyChildAttach, myTaskScheduler);
var task = factory.StartNew(() => MyCodeAsync()).Unwrap();

При желании я написал несколько Run перегрузок для TaskFactory, которые делают использование TaskFactory более похожим на Task.Run:

// Equivalent to the above code
var factory = new TaskFactory(CancellationToken.None, TaskCreationOptions.DenyChildAttach,
    TaskContinuationOptions.DenyChildAttach, myTaskScheduler);
var task = factory.Run(() => MyCodeAsync());
...