如何获取不在UI线程上执行的任务

以下代码是实际应用程序中代码的简化。 下面的问题是将在UI线程中运行长时间的工作,而不是后台线程。

void Do() { Debug.Assert(this.Dispatcher.CheckAccess() == true); Task.Factory.StartNew(ShortUIWork, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); } void ShortUIWork() { Debug.Assert(this.Dispatcher.CheckAccess() == true); Task.Factory.StartNew(LongWork, TaskCreationOptions.LongRunning); } void LongWork() { Debug.Assert(this.Dispatcher.CheckAccess() == false); Thread.Sleep(1000); } 

所以Do()通常是从UI上下文中调用的。 ShortUIWork也是如此,由TaskScheduler定义。 但是,LongWork最终也会在UI线程中调用,当然,它会阻止UI。

如何确保UI线程中没有运行任务?

LongRunning只是对TaskScheduler一个提示。 对于SynchronizationContextTaskScheduler (由TaskScheduler.FromCurrentSynchronizationContext()返回),它显然忽略了提示。

一方面,这似乎违反直觉。 毕竟,如果任务长时间运行,则不太可能希望它在UI线程上运行。 另一方面,根据MSDN:

LongRunning – 指定任务将是长时间运行的粗粒度操作。 它向TaskScheduler提供了一个提示,即可以保证超额订阅。

由于UI线程不是线程池线程,因此不会出现“超额订阅”(线程池饥饿),因此提示对SynchronizationContextTaskScheduler没有任何影响。

无论如何,您可以通过切换回默认任务调度程序来解决此问题:

 void ShortUIWork() { Debug.Assert(this.Dispatcher.CheckAccess() == true); Task.Factory.StartNew(LongWork, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); }