C# 如何从自定义TaskScheduler回退到默认TaskScheduler
假设我想创建一个自定义TaskScheduler,但在它内部,如果某些条件不适用,则返回默认值。我该怎么做 例如C# 如何从自定义TaskScheduler回退到默认TaskScheduler,c#,.net,task-parallel-library,C#,.net,Task Parallel Library,假设我想创建一个自定义TaskScheduler,但在它内部,如果某些条件不适用,则返回默认值。我该怎么做 例如 受保护的覆盖无效队列任务(任务任务){ 如果(/*某些条件*/){ /*手动安排任务,无所谓*/ } /*默认情况下的队列任务--如何*/ } 受保护的重写IEnumerable GetScheduledTasks(){ 返回Enumerable.Concat(/*我的任务*/,/*默认任务--如何?*/); } 我认为你不能(或不应该)这样做,即使你求助于反射黑客。理论上,您需要从
受保护的覆盖无效队列任务(任务任务){
如果(/*某些条件*/){
/*手动安排任务,无所谓*/
}
/*默认情况下的队列任务--如何*/
}
受保护的重写IEnumerable GetScheduledTasks(){
返回Enumerable.Concat(/*我的任务*/,/*默认任务--如何?*/);
}
我认为你不能(或不应该)这样做,即使你求助于反射黑客。理论上,您需要从现有的非抽象任务调度器派生自定义的TaskScheduler
,例如
但是,您不能这样做,因为TPL中的任务调度器是私有的
或内部的
在使用TaskScheduler.QueueTask
的情况下,可能很容易将调用转发到:
然而,你也不能这样做。内部调用TaskScheduler.QueueTask
,这将导致无限递归
此外,Task
对象在Task.Start
中存储对任务调度器的引用。因此,假设您使用反射调用ThreadPoolTaskScheduler.QueueTask
,它将中断任务与其任务调度器之间的连接
因此,
QueueTask
、GetScheduledTasks
和TaskScheduler
的一些其他方法被声明为受保护的。如果你想实现一个自定义任务调度程序,你必须提供完整的实现。我明白你为什么说我不能这样做,但你为什么认为我不应该这样做?@AndreyShchekin,出于这个原因:任务
对象在任务.启动
中存储了对任务调度程序的引用。如果使用自定义任务计划程序启动任务(通过task.start
或task.Factory.StartNew
),将存储对任务计划程序的引用。然后在您的QueueTask
中调用defaultTaskScheduler.QueueTask
,任务将在不同的任务调度器上运行,而不是保留引用。这样做的结果可能是不可预测的。我认为它与任何普通的装饰程序没有什么不同——对于外部世界来说,任务实际上是在我的调度程序上运行的,只是它的内部实现使用了另一个调度程序来帮助这一点。另一方面,我认为ThreadPoolScheduler在从另一个调度器传递任务时抛出。无论如何,整个API在可扩展性方面似乎设计得非常糟糕。谢谢你的回答——我同意这个问题没有好的解决方案。
protected override void QueueTask(Task task) {
if (/* some condition */) {
/* schedule task manually, does not matter */
}
/* queue task on default -- how? */
}
protected override IEnumerable<Task> GetScheduledTasks() {
return Enumerable.Concat(/* my tasks */, /* tasks from default -- how? */);
}
protected override void QueueTask(Task task) {
if (/* some condition */) {
/* schedule task manually, does not matter */
}
/* queue task on default -- how? */
task.Start(TaskScheduler.Default);
}