2015-12-06 19 views
2
Task t = new Task(() => 
{ 
    //I would expect this to be on a worker thread, but it's not! 
    Thread.Sleep(1000); 
}); 

Task test = new Task(() => 
{ 
    Thread.Sleep(1000); 
}); 

test.ContinueWith(x => 
{ 
    //Do some UI Updates here, but also start another Task running. 
    t.Start(); 
}, TaskScheduler.FromCurrentSynchronizationContext()); 

test.Start(); 

为什么t在UI线程上被调用。据我所知,我创建了一个Tasktest,它正确地在UI线程上调用,但我然后开始一个新的任务运行。现在我知道我可以通过指定TaskScheduler.Default作为针对t.Start的重载方法来解决此问题,但为什么新的Task在ui线程上开始?为什么在UI上调用启动一个新的任务线程

+1

一般提示:没有理由自己使用任务构造函数。 – Voo

回答

5

但为什么新Task拿到UI线程上开始了吗?

因为,除非另有规定,呼吁任务时间表Start对当前TaskScheduler任务而你的情况是在一个公正的门面,你使用TaskScheduler.FromCurrentSynchronizationContext()创建UI线程的SynchronizationContext

开始Task,安排它执行到当前的TaskScheduler

Task.Start Method

如果你想这个任务要在不同TaskScheduler比当前的计划,你可以把它作为一个参数:

t.Start(TaskScheduler.Defualt); 

注:有几乎无可想象的使用Task.Start是最佳解决方案。你应该重新考虑这条道路。

+1

欲了解更多信息,请参阅Stephen Cleary的博客文章“[StartNew is Dangerous](http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html)”,具体地“为什么不使用Task.Factory.StartNew”部分。它讨论的是Task.Factory.StartNew而不是Task.Start,但是潜在的问题(为“ContinueWith”内的当前任务调度器调度任务)是相同的。 –

+0

我还是有点困惑。我在哪个时候改变了TaskScheduler?我告诉继续在UI线程上运行。但我永远不会告诉't'在UI线程上运行。 – William

+0

@William您可以安排使用'TaskScheduler.FromCurrentSynchronizationContext'创建的'TaskScheduler'的延续。当延续运行时,此调度程序是当前调度程序。所以当你调用'Start'时''TaskScheduler.Current'是你的特殊调度器,它将任务发布到UI线程。 – i3arnon

3

请勿使用Task.Start方法。另外,如果你想延迟一个任务中使用Task.Delay这样的:

Task.Delay(TimeSpan.FromSeconds(1)) //Wait 1 second 
    .ContinueWith(t => DoSomeUIWork(), TaskScheduler.FromCurrentSynchronizationContext()) //execute something on the UI thread 
    .ContinueWith(t => DoSomeBackgroundWork()); //Then do some background work 
+3

这应该是一个评论,而不是答案,StartNew也会有相同的行为。 –

+0

但是,这将开始立即运行的任务,这不是我想要的行为。 – William

+0

@William,我已经更新了答案 –

相关问题