Во-первых, имейте в виду, что 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());