我一直试图弄清楚UI为什么会阻塞ViewModel方法,并意识到这部分代码:
await Task.WhenAll(getOutput1(), getOutput2());
是问题所在。我设法通过使用:
取消阻止用户界面await Task.WhenAll(Task.Run(() => getOutput1()), Task.Run(() => getOutput2()));
getOutput1()
和getOutput2()
都是async
,其中Task
返回类型在ViewModel中,代码从视图中调用。
当我调用Task.Run()并直接提供任务时调用Task.WhenAll的区别是什么?
答案 0 :(得分:2)
如果方法是纯异步操作,那么在从UI线程调用它们时不应该使用Task.Run,它将正常工作。
但是,如果这些方法也涉及长时间运行的CPU绑定工作,则在执行异步I / O操作时将不会阻止UI线程,但在CPU绑定工作时将不会阻止该线程。
在这种情况下,您需要在调用方法时使用Task.Run,即使方法看起来像异步方法,因为这些方法实际上是同步和异步操作的组合,并且您不希望在阻止UI时同步工作完成。
另一个选择而不是使用ViewModel中的Task.Run是在等待方法中的I / O异步操作时使用ConfigureAwait(false),这样做会在等待它不需要的部分后通知方法的其余部分它具有的原始上下文(可能是UI一个),并且该方法的其余部分也可以在另一个ThreadPool线程中执行。
有关异步和等待结合I / O和CPU绑定工作的方法的更多信息,请参阅this问题。
答案 1 :(得分:2)
当我调用Task.Run()并直接提供任务时调用Task.WhenAll会有什么不同?
直接调用方法将在UI线程上调用它们。从Task.Run
内调用它们将在线程池线程上调用它们。
结论:getOutput1
和/或getOutput2
实际上并不是异步的。 (一个方法完全有可能返回Task
- 因此出现异步 - 但实际上只是同步阻塞。“