C# 为什么在UI线程上调用启动新任务

C# 为什么在UI线程上调用启动新任务,c#,.net,multithreading,task-parallel-library,C#,.net,Multithreading,Task Parallel Library,为什么在UI线程上调用t。我知道我针对test创建了一个continuationTask,该任务在UI线程上被正确调用,但我随后开始运行一个新任务。现在我知道我可以通过指定TaskScheduler.Default作为针对t.Start的重载方法来解决这个问题,但是为什么要在ui线程上启动新的Task呢?不要使用Task.Start方法。另外,如果您想延迟一项任务,请使用task.delay如下: Task t = new Task(() => { //I would expect

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

不要使用
Task.Start
方法。另外,如果您想延迟一项任务,请使用
task.delay
如下:

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();
但是为什么要在ui线程上启动一个新的
任务

因为除非另有规定,否则在任务上调用
Start
会在当前
TaskScheduler
上调度任务,在您的情况下,该任务只是UI线程的
SynchronizationContext
上的一个门面,该线程是使用
TaskScheduler.FromCurrentSynchronizationContext()
创建的

启动
任务
,将其调度到当前的
任务调度程序

如果希望将该任务安排在与当前任务不同的
TaskScheduler
上,可以将其作为参数传递:

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


注意:使用
Task.Start
是解决此问题的最佳方案,这几乎是不可能的。您可能应该重新考虑这条途径。

这应该是一条评论,而不是一个答案,StartNew也会有同样的行为。但这将立即启动任务运行,这不是我想要的行为。有关进一步阅读,请参阅Stephen Cleary的博文“”,具体是“为什么不使用task.Factory.StartNew”一节。它讨论的是
Task.Factory.StartNew
而不是
Task.Start
,但基本问题(在
ContinueWith
中为当前任务计划程序安排任务)是相同的。我仍然有点困惑。我在哪一点上更改了TaskScheduler?我告诉继续在UI线程上运行。但是我从来没有告诉
t
在UI线程上运行。@William您在用
TaskScheduler.FromCurrentSynchronizationContext
创建的
TaskScheduler
上安排继续。此计划程序是继续运行时的当前计划程序。因此,当您调用
Start
TaskScheduler时,Current
是您将任务发布到UI线程的特殊调度程序。这很有意义。但是currentSynchronizationContext的
方法从来没有建议(仅从它的名称)它应该改变任何状态,但我想它确实改变了。谢谢你answer@William没有。。没有。“更改状态”是指您明确地在特定的
任务调度器上调度任务。当你这么做的时候。。任务将在该计划程序上运行,该计划程序将是当前计划程序,并将存储在
TaskScheduler.current
。一般提示:没有理由自己使用任务构造函数。
t.Start(TaskScheduler.Defualt);