【问题标题】:which is the difference between task.whenAll and configurewait?task.whenAll 和 configurewait 有什么区别?
【发布时间】:2018-06-08 19:32:07
【问题描述】:

我有一个从数据库中获取数据的异步方法:

private async Task getDataAsync()
{
    await getDataFromDatabaseAsync();
}

我有一个使用这种方法的构造器,以这种方式:

public MyViewModel()
{
    Task.WhenAll(getDataAsync());
    //getDataAsync().ConfigureAwait(false);

    //next line of code
}

避免应用程序不被阻止的唯一方法是使用两个选项之一,这两个选项似乎都可以正常工作。我可以使用WhenAll,也可以使用ConfigureAwait(false)。

另一个选项是在任务中调用 getDataASync() 方法,但我想这是一个更糟糕的选项,因为它需要更多资源。

所以我想知道WhenAll和ConfigureAwait之间的区别。

当我以这种方式使用WhenAll时,“下一行代码”这行代码是在异步方法完成之后运行还是在完成之前运行?

谢谢。

【问题讨论】:

  • 看起来你只是想绕开你不能在构造函数中调用异步代码的事实。最好不要这样做并重新编写代码。
  • Task.WhenAll() 将运行所有传递的任务以完成。任务完成后,ConfigureAwait(false) 不会与同步上下文同步。
  • ConfigureAwait 是关于同步上下文的,与“阻塞”无关。您在这里将异步编程与并行执行混合在一起。这不是一回事。 Task.WhenAll 接受一些任务并让它们运行只要它需要并在所有完成后返回。 await 的行为与一项任务类似,ConfigureAwait 只是告诉它使用哪个上下文。
  • 这是在 STA 中运行的吗?例如WPF 调度程序?

标签: c# async-await


【解决方案1】:

有一个常见的误解,即当您创建一个方法async 时,它实际上会异步执行(即在单独的线程上)。情况并非如此:asyncawait 是一种同步已经异步代码的方法。如果您没有在单独的线程上执行任何操作,您的 async 代码将完全同步运行到最后。

由于getDataAsyncMyViewModel 构造函数在同一线程上执行,您可能会遇到死锁,因为线程会等待自己。当您使用ConfigureAwait 时,您可以避免这种情况。

你是否真的应该这样做是一个不同的问题。您实际上对ConfigureAwait 所做的是启动任务并允许等待在单独的上下文(可以在单独的线程上)上继续。除了您在这里甚至没有使用await 之外,当您想要在等待之后执行 UI 操作时,在不同的上下文中继续可能会成为一个问题。

如果你想确保你可以在你的构造函数中等待getDataAsync,你可以使用Task.Run在线程池中强制执行:

var getDataTask = Task.Run((Func<Task>)getDataAsync);
//Do something else
getDataTask.Wait();

您在Task.RunWait() 之间执行的所有操作都可以在getDataAsync 执行期间运行。并行性是否真的值得在这里取决于您在Wait() 之前还做了什么。

你在MyViewModel构造函数中所做的是最终同步所有异步操作并使构造函数的执行同步。如果您想异步运行该操作,则需要启动 another 任务来执行此操作。因此,您应该非常确定在此之后不再需要 async。如果是,请在另一个 async 方法上运行初始化,await getDataAsync() 并在调用链的某个位置进行同步。

【讨论】:

  • 但是在构造函数中我不能使用 await 关键字。我不确定在 .net 的最新版本中是否可以这样做,这对我来说可能是一个选择,因为我可以使用更新的版本。
  • 出于这个原因,您应该使用激活概念 - 有一个命令(我假设您使用它们,因为该类称为 ViewModel)并在显示 ViewModel 后执行它。不要在构造函数中使用它。
猜你喜欢
  • 1970-01-01
  • 2017-02-28
  • 2017-03-04
  • 2010-10-02
  • 2011-12-12
  • 2010-09-16
  • 2012-03-14
  • 2012-02-06
  • 2011-02-25
相关资源
最近更新 更多