我有从数据库获取产品的任务,以及操作某些UI修改的ContinueWith
操作,因此我遇到了问题,因为Task创建了一个新线程,并且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());
它有效。那有什么不同呢?为什么我的第一个代码不起作用? 谢谢!
答案 0 :(得分:15)
来自TaskScheduler.Current
的文档:
如果未在任务中调用,则Current将返回Default调度程序。
然后从Task Schedulers documentation:
任务并行库和PLINQ的默认调度程序使用.NET Framework ThreadPool来排队和执行工作。
因此,如果您在不在任务中时使用TaskScheduler.Current
,您将获得一个使用线程池的调度程序。
如果您致电TaskScheduler.FromCurrentSynchronizationContext()
,您将获得当前synchronization context的一个 - 在Windows窗体或WPF中(从UI线程调用时)是在相关UI上安排工作的上下文线程。
这就是为什么第一个代码不起作用的原因:它在线程池线程上执行了你的延续。你的第二个代码在UI线程上执行了延续。
请注意,如果你可以使用C#5和async / await,那么所有这些都可以更简单地处理很多。