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

时间:2012-03-17 07:38:37

标签: c# wpf task-parallel-library

以下代码是对实际应用程序中代码的简化。下面的问题是将在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线程中没有运行任务?

1 个答案:

答案 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);
}