自定义 TaskScheduler 上的问题 scheduling/starting 任务,它将在所述调度程序上完成执行

Problems scheduling/starting task on a custom TaskScheduler, which will complete execution on said Scheduler

我要安排的工作正在使用 await 关键字,因此工作本身的类型为 async Task

我不能使用 Task.Factory.StartNew,即使我通过了我的调度程序,因为它会在遇到工作的第一个等待时考虑任务 "done",使其离开调度程序并且继续使用默认调度程序。

我不能使用 var a = new Task(DoWork....); a.Start(myScheduler),因为我会使用 async void 方法,我们知道其中的陷阱。

我无法使用 Task.Run(),因为它不允许您更改计划启动任务的调度程序。

如果我不能使用其中任何一个,我将如何实现我的目标,即安排我的异步工作,它必须在它最初启动的调度程序上完成执行?

首先,请注意 TaskScheduler 仅适用于 正在执行的 任务。因此,当使用 async 委托时,TaskScheduler 将仅在 await 点之间使用;当 async 代码(异步)在 await 中等待时,则没有代码 "in" 该调度程序。对于某些调度程序,这不是问题,但对于像 ConcurrentExclusiveSchedulerPair 这样的调度程序来说,这是一个问题,因为代码不是 "in" await 期间的调度程序。

如果您的 TaskScheduler 将按预期使用 async 代码工作,那么您可以通过调用 Task.Factory.StartNew 并传递 [=12] 在其上创建一个任务 运行 =].这将 return 变成 Task<Task>Task<Task<T>> 因为 StartNew 不理解 async 代码;您可以对该值调用 Unwrap() 以获得 "normal" 异步 Task/Task<T>.

就个人而言,我更喜欢使用您自己的 TaskScheduler(和其他选项)创建您自己的 TaskFactory 实例,然后使用 Unwrap 调用该 StartNew。例如:

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

如果需要,我写了一些 Run overloads for 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());