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

Tom*_*mba 11 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);
    }
Run Code Online (Sandbox Code Playgroud)

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

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

Ken*_*art 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);
}
Run Code Online (Sandbox Code Playgroud)