【问题标题】:Difference between Task.WhenAll(Task.Run(async method)) and Task.WhenAll(async method)Task.WhenAll(Task.Run(async method)) 和 Task.WhenAll(async method) 的区别
【发布时间】:2017-02-28 17:33:49
【问题描述】:

我一直试图找出 UI 被 ViewModel 方法阻塞的原因,并意识到这部分代码:

await Task.WhenAll(getOutput1(), getOutput2());

是问题所在。我设法通过以下方式解除对 UI 的阻止:

await Task.WhenAll(Task.Run(() => getOutput1()), Task.Run(() => getOutput2()));

getOutput1()getOutput2()在ViewModel中都是async,返回类型为Task,代码是从View中调用的。

当我调用 Task.Run() 并直接提供任务时调用 Task.WhenAll 有什么区别?

【问题讨论】:

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

标签: c# multithreading user-interface uwp


【解决方案1】:

当我调用 Task.Run() 并直接提供任务时调用 Task.WhenAll 有什么区别?

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

结论:getOutput1 和/或getOutput2 实际上并不是异步的。 (一个方法完全有可能返回 Task - 因此 appear 异步 - 但实际上只是同步阻塞)。

【讨论】:

    【解决方案2】:

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

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

    在这种情况下,您需要在调用方法时使用 Task.Run,​​即使这些方法已经看起来像异步方法,因为这些方法实际上是同步和异步操作的组合,并且您不想阻塞 UI 而同步工作已完成。

    从 ViewModel 中使用 Task.Run 的另一种选择是在等待方法中的 I/O 异步操作时使用 ConfigureAwait(false),这样做会在等待部分之后通知方法的其余部分它不需要原始它具有的上下文(可能是 UI 上下文),并且该方法的其余部分也可以在另一个 ThreadPool 线程中执行。

    请参阅this 问题以获取有关结合 I/O 和 CPU 绑定工作的 async 和 await 方法的更多信息。

    【讨论】:

      猜你喜欢
      • 2013-10-06
      • 2021-12-29
      • 1970-01-01
      • 2017-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-01
      • 1970-01-01
      相关资源
      最近更新 更多