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

Why does starting a new Task get invoked on the UI Thread

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 线程上被调用。我知道我针对 test 创建了一个延续 Task,它在 UI 线程上被正确调用,但我随后开始了一个新任务 运行。现在我知道我可以通过将 TaskScheduler.Default 指定为针对 t.Start 的重载方法来解决这个问题,但是为什么新的 Task 在 ui 线程上启动?

不要使用 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

but why does a new Task get started on the ui thread?

因为除非另有说明,否则在任务上调用 Start 会在当前 TaskScheduler 上安排任务,在您的情况下,这只是 UI 线程的 SynchronizationContext 的外观您使用 TaskScheduler.FromCurrentSynchronizationContext().

创建的

Starts the Task, scheduling it for execution to the current TaskScheduler.

来自Task.Start Method

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

t.Start(TaskScheduler.Defualt);

注意:几乎没有任何情况可以想象使用 Task.Start 是最佳解决方案。你可能应该重新考虑这条路。