以下代码是对实际应用程序中代码的简化。下面的问题是将在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);
}
因此,从UI上下文中正常调用Do()。 ShortUIWork也是如此,由TaskScheduler定义。但是,LongWork最终也会在UI线程中调用,当然,这会阻止UI。
如何确保UI线程中没有运行任务?
答案 0 :(得分:9)
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);
}