Async/Await:ConfigureAwait 的意外行为
本文关键字:意外 ConfigureAwait Await Async | 更新日期: 2023-09-27 18:32:26
如果在 MVC ASP.NET 中执行以下代码,则可以在调试窗口中看到它将在 await
后正确还原线程的区域性,即使 ManagedThreadId 发生更改也是如此:
public async Task<ActionResult> Index()
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(Thread.CurrentThread.CurrentUICulture);
await SomeMethod();
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(Thread.CurrentThread.CurrentUICulture);
return View();
}
private async Task SomeMethod()
{
await Task.Delay(100).ConfigureAwait(false);
}
然后我只是将 ConfigureAwait(false) 从 SomeMethod() 移动到 Index(),除此之外,它与上面的代码相同:
public async Task<ActionResult> Index()
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(Thread.CurrentThread.CurrentUICulture);
await SomeMethod().ConfigureAwait(false);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(Thread.CurrentThread.CurrentUICulture);
return View();
}
private async Task SomeMethod()
{
await Task.Delay(100);
}
现在它不会恢复我的文化,但总是将其设置为 new CultureInfo("en-US")
.但我希望使用这两种方法,结果必须相同。绝对不清楚为什么会发生这种情况。
如果您使用 await task.ConfigureAwait(false)
,那么该方法的其余部分(以及您从那里调用的任何内容)将不会在原始上下文中执行。但这不会影响逻辑调用树中更高位置的任何代码。
我认为这是唯一合乎逻辑的方法。如果更高的代码必须在原始上下文中执行(这很常见),那么库代码深处的ConfigureAwait()
真的不应该影响它。
为了使这一点更具体,如果按照您的行为ConfigureAwait()
则在 WinForms 中使用 await
的以下简单示例将不起作用:
async void ButtonClicked(object sender, EventArgs e)
{
textBlock.Text = "Downloading";
await DownloadAsync();
textBlock.Text = "Finished";
}
async Task DownloadAsync()
{
data = await new HttpClient().GetStringAsync(url).ConfigureAwait(false);
}
您可以创建自己的等待者,以使用await
延续回调使区域性流,即使它发生在不同的池线程上也是如此。因此,您的呼叫将如下所示:
await SomeMethod().WithCulture();
Stephen Toub在PFX团队博客上展示了如何做到这一点,寻找CultureAwaiter
。
(来自手机)
您不仅会失去线程文化。你正在失去整个上下文。
当存在同步上下文时,延续将发布到该同步上下文。在 ASP.NET 中,这是一个请求处理程序线程,在客户端 UI 中,这是一个 UI 线程。
ConfigureAwait(false) 指示生成的状态机不要发布到捕获的(如果有)同步上下文。
索引永远不应该使用它,但从那里调用的任何代码都应该使用它。