【问题标题】:Is this the correct way to use ConfigureAwait(false)?这是使用 ConfigureAwait(false) 的正确方法吗?
【发布时间】:2020-02-18 16:53:38
【问题描述】:

我正在构建一个 WPF 应用程序并调用此自定义事件。 这里的问题是我应该在任何地方打电话给ConfigureAwait(false)吗?正如您现在所看到的,我将其称为 2 次。甚至在第二种方法中使用双 ConfigureAwait(false) 在同一行中的 3 次。

// First approach
void RaiseProcessEvent(object sender, EventArgs e)
{
    Task.Run(async () => await APIManager.GetInstance.ProcessMethod()).ConfigureAwait(false);
}

// Second approach
void RaiseProcessEvent(object sender, EventArgs e)
{
    Task.Run(async () => await APIManager.GetInstance.ProcessMethod().ConfigureAwait(false)).ConfigureAwait(false);
}

// This function is in a singleton class
public async Task ProcessMethod()
{
    var result = await GetInstance.GetFinalResultFromHttpClientAsync().ConfigureAwait(false);     
}

【问题讨论】:

  • 可以是一个粘性主题,查看https://johnthiriet.com/configure-await/ 看看这是否对您的方案有帮助
  • 是的,我以前读过。它有点令人困惑,一些或大多数网站都说“尽你所能”,所以我只是想为了添加而添加。就个人而言,我觉得没有任何不同

标签: c# wpf asynchronous async-await


【解决方案1】:

这里的问题是我应该在任何地方都调用 ConfigureAwait(false) 吗?

一般来说,ConfigureAwait(false) should be used if the method does not need to resume on its calling context。是否使用ConfigureAwait(false) 的决定应该基于每个方法做出,并且应该用于该方法中的每个await,或者不应该用于该方法中的每个await

更务实的是,ConfigureAwait(false) 应该用在旨在重用的代码中,可能在不同的上下文中。应用程序代码很少需要使用ConfigureAwait(false),尽管我遇到过需要prevent having a bunch of continuations interrupting the UI thread 的情况。

您现在可以看到我打了 2 次电话。甚至在第二个方法中使用双配置(false)在同一行中的 3 次。

在这些情况下,ConfigureAwait(false) 毫无意义。原因如下:

//first approach
Task.Run(async () => await APIManager.GetInstance.ProcessMethod()).ConfigureAwait(false);

ConfigureAwait 配置一个await。它不配置任务。由于从Task.Run 返回的任务永远不会是awaited,所以这个ConfigureAwait 什么都不做。

//second approach
Task.Run(async () => await APIManager.GetInstance.ProcessMethod().ConfigureAwait(false)).ConfigureAwait(false);

ConfigureAwait(false)false 部分用于continueOnCapturedContext 参数。所以ConfigureAwait(false) 是说“这个方法不需要在捕获的上下文上继续”。但在这种情况下,async 委托在线程池上运行(Task.Run 就是这样做的),所以您知道无论如何都没有要捕获的上下文。

旁注1:当使用Task.Run调用异步方法时,elide the async and await keywords很常见。例如:Task.Run(() => APIManager.GetInstance.ProcessMethod());。所以ConfigureAwait(false) 的问题无论如何都变得毫无意义,因为不再有await

旁注2:丢弃从Task.Run 返回的任务意味着代码正在执行即发即弃,这几乎总是一个可怕的错误。除此之外,这意味着任何异常都会被默默地吞下。使用await 几乎总是更好:

async void RaiseProcessEvent(object sender, EventArgs e)
{
  await Task.Run(() => APIManager.GetInstance.ProcessMethod());
}

现在有一个await 用于从Task.Run 返回的任务,所以此时问这个问题是合适的:这个await 是否应该使用ConfigureAwait(false)?这里的意见可能会有所不同,但我会说不,因为这显然是应用程序级代码(UI 事件处理程序),并且大多数开发人员会假设运行事件处理程序的代码将在 UI 线程上(即使有 @987654357 @以前在该方法中)。因此,为了获得最大的可维护性,我不会在 UI 事件处理程序方法中使用 ConfigureAwait(false),除非出于性能原因必须添加它。

【讨论】:

  • 嗨,你的解释很清楚。是的,fire and throw 是我需要的,因为我的 ProcessMethod 正在调用一个 Httpclient,我在里面有一个 try catch 用于记录目的。所以我可以在 task.run 之后安全地删除该方法
【解决方案2】:

欢迎来到 SO!

如果您正在编写应用程序代码,那么您可能根本不应该使用它。 MSDN 上的ConfigureAwait FAQ 对此有很大的讨论。

TL;DR:

如果您正在编写通用库,请使用 ConfigureAwait(false) / app-model-agnostic 代码,否则不要。

也就是说,这是一个有点复杂的话题,所以我相信这里会有很多其他人不同意。我已经编写了一些极其复杂的多任务 WPF 应用程序,但我一时想不起来我实际上需要在应用程序代码中使用它的任何情况。

【讨论】:

  • 您好,感谢您的回复。意思是说我不需要configureawait,因为我没有更新UI?因为我的代码只是在后端做一些处理,我不希望它阻塞 UI。而dispatcher主要是更新UI?
  • 呃...鉴于Stephen Cleary 刚刚振作起来,我认为退出这篇文章对我来说可能是明智的。非常缓慢地! :D
猜你喜欢
  • 2019-11-14
  • 2012-05-11
  • 2018-12-31
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多