自定义 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());
我要安排的工作正在使用 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());