C# Task.WhenAll(Task.Run(异步方法))和Task.WhenAll(异步方法)之间的差异

C# Task.WhenAll(Task.Run(异步方法))和Task.WhenAll(异步方法)之间的差异,c#,multithreading,user-interface,uwp,C#,Multithreading,User Interface,Uwp,我一直在试图找出UI为什么会被ViewModel方法阻塞,并意识到这部分代码: await Task.WhenAll(getOutput1(), getOutput2()); 这就是问题所在。我使用以下方法成功解除了对UI的阻止: await Task.WhenAll(Task.Run(() => getOutput1()), Task.Run(() => getOutput2())); getOutput1()和getOutput2()都是视图模型中带有Task返回类型的asy

我一直在试图找出UI为什么会被ViewModel方法阻塞,并意识到这部分代码:

await Task.WhenAll(getOutput1(), getOutput2());
这就是问题所在。我使用以下方法成功解除了对UI的阻止:

await Task.WhenAll(Task.Run(() => getOutput1()), Task.Run(() => getOutput2()));
getOutput1()
getOutput2()
都是视图模型中带有
Task
返回类型的
async
,代码从视图中调用


调用Task.whalll时调用Task.Run()和直接提供任务有什么区别?

如果这些方法是纯异步操作,那么您不应该使用Task.Run,同时从UI线程调用它们,它将正常工作。

但是,如果这些方法还涉及长时间运行的CPU绑定工作,则在执行异步I/O操作时,UI线程不会被阻塞,而是在执行CPU绑定工作时被阻塞。

在这种情况下,您需要使用任务。在调用方法时运行,即使这些方法看起来已经是异步的,因为这些方法实际上是同步和异步操作的组合,并且您不希望在同步工作完成时阻塞UI。

另一个不使用Task.RunfromViewModel的选项是在等待方法中的I/O异步操作时使用,这样做将通知等待部分之后的方法的其余部分它不需要它拥有的原始上下文(可能是UI上下文)方法的其余部分也可以在另一个线程池线程中执行。


有关结合I/O和CPU绑定工作的异步和等待方法的更多信息,请参阅问题

如果这些方法是纯异步操作,则不应使用Task.Run,同时从UI线程调用它们,它将正常工作。

但是,如果这些方法还涉及长时间运行的CPU绑定工作,则在执行异步I/O操作时,UI线程不会被阻塞,而是在执行CPU绑定工作时被阻塞。

在这种情况下,您需要使用任务。在调用方法时运行,即使这些方法看起来已经是异步的,因为这些方法实际上是同步和异步操作的组合,并且您不希望在同步工作完成时阻塞UI。

另一个不使用Task.RunfromViewModel的选项是在等待方法中的I/O异步操作时使用,这样做将通知等待部分之后的方法的其余部分它不需要它拥有的原始上下文(可能是UI上下文)方法的其余部分也可以在另一个线程池线程中执行。

有关结合I/O和CPU绑定工作的异步和等待方法的更多信息,请参阅问题

调用Task.whalll时调用Task.Run()和直接提供任务有什么区别

直接调用这些方法将在UI线程上调用它们。从
Task.Run中调用它们将在线程池线程上调用它们

结论:
getOutput1
和/或
getOutput2
实际上不是异步的。(方法完全可以返回
任务
,因此看起来是异步的,但实际上只是同步块)

调用Task.whalll时调用Task.Run()和直接提供任务有什么区别

直接调用这些方法将在UI线程上调用它们。从
Task.Run中调用它们将在线程池线程上调用它们


结论:
getOutput1
和/或
getOutput2
实际上不是异步的。(一个方法完全可以返回
Task
,因此看起来是异步的,但实际上只是同步块)。

如果
getOutput1
getOutput2
都是“真正”异步的,那么第一个选项必须正常工作。你能展示一下这些方法吗?请注意,如果您没有读取“IO”操作,异步方法将同步执行。这完全取决于
getOutput1
getOutput2
的性质。如果他们在没有调用任何异步行为的情况下完成了大量工作,那么这些工作将在代码版本1中的原始线程上完成。@Damien_不相信你的话,实际上你是对的,我只在方法中的UI线程上调度时才调用异步行为。感谢您的见解如果
getOutput1
getOutput2
都是“真正”异步的,那么第一个选项必须正常工作。你能展示一下这些方法吗?请注意,如果您没有读取“IO”操作,异步方法将同步执行。这完全取决于
getOutput1
getOutput2
的性质。如果他们在没有调用任何异步行为的情况下完成了大量工作,那么这些工作将在代码版本1中的原始线程上完成。@Damien_不相信你的话,实际上你是对的,我只在方法中的UI线程上调度时才调用异步行为。谢谢你的洞察力