11

我有一个从数据库获取产品的任务,以及ContinueWith操作一些 UI 修改的操作,因此我遇到了问题,因为任务创建了一个新线程,并且 UI 修改不是在 UI 线程中执行的。

我尝试使用此修复程序:

var currentScheduler = TaskScheduler.Current;

Task.Factory.StartNew(() =>
{    
    // get products   
}).ContinueWith((x) => handleProductsArrived(x.Result, x.Exception), currentScheduler);

但它根本没有用。我检查并ContinueWith没有在 currentScheduler 的线程中执行,而是在另一个线程中执行。

我发现了这个方法:

Task.Factory.StartNew(() =>
{
    // get products
}).ContinueWith((x) => handleProductsArrived(x.Result, x.Exception), TaskScheduler.FromCurrentSynchronizationContext());

它有效。那么有什么区别呢?为什么我的第一个代码不起作用?谢谢!

4

1 回答 1

21

从文档中TaskScheduler.Current

当未从任务中调用时,Current 将返回默认调度程序。

然后从任务计划程序文档中:

任务并行库和 PLINQ 的默认调度程序使用 .NET Framework 线程池来排队和执行工作。

因此,如果您TaskScheduler.Current在不参与任务时使用,您将获得一个使用线程池的调度程序。

如果您调用TaskScheduler.FromCurrentSynchronizationContext(),您将获得一个当前同步上下文- 在 Windows 窗体或 WPF 中(当从 UI 线程调用时)是在相关 UI 线程上安排工作的上下文。

这就是为什么第一个代码不起作用的原因:它在线程池线程上执行了您的延续。您的第二个代码在 UI 线程上执行了延续。

请注意,如果您可以使用 C# 5 和 async/await,则所有这些都可以简单地处理。

于 2013-04-16T08:29:43.220 回答