Async/Await: Unexpected behaviour of ConfigureAwait

无人久伴 提交于 2020-01-13 12:13:07

问题


If you execute the following code in ASP.NET MVC, you can see in Debugging Window that it will correctly restore the thread's culture after await, even if ManagedThreadId changes:

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);
}

Then I just move ConfigureAwait(false) from SomeMethod() to Index(), except for this, it's the same code as above:

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);
}

Now it doesn't restore my culture but always set it to new CultureInfo("en-US"). But I expect that using both methods, the result must be the same. It's absolutely unclear, why it's happening.


回答1:


If you use await task.ConfigureAwait(false), then the rest of that method (and whatever you call from there) will not execute on the original context. But this won't affect any code higher up in the logical call tree.

And I think this is the only logical way to do it. If the code higher up has to be executed on the original context (which is quite common), then ConfigureAwait() somewhere deep inside library code really shouldn't affect it.

To make this more concrete, the following simple example of using await in Winforms wouldn't work if ConfigureAwait() behaved according to you:

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);
}



回答2:


You can create your own awaiter to make the culture flow with await continuation callback, even when it takes place on a different pool thread. So, your call would look like:

await SomeMethod().WithCulture();

Stephen Toub shows exactly how to do this on the PFX Team blog, look for CultureAwaiter.




回答3:


(from a mobile phone)

You're not only losing the thread culture. You're losing the whole context.

When in the presence of a SynchronizationContext, the continuation is posted to that SynchronizationContext. In ASP.NET that's a request handler thread, in client UIs that's the UI thread.

ConfigureAwait(false) instructs the generated state machine to not post to the captured (if any) SynchronizationContext.

Index should never use it but any code being called from there should.



来源:https://stackoverflow.com/questions/18970400/async-await-unexpected-behaviour-of-configureawait

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!