29

让我们看一些简单的 C# async/await 代码,其中我在withobj之前和之后都有一个对象引用 ( )awaitConfigureAwait(false)

private async Task<SomeObject> AnAsyncLibraryMethod(SomeObject obj)
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    obj.Name = "Harry"; // <-- obj here

    // MAIN POINT
    var newSubObj = await FetchOverHttpAsync().ConfigureAwait(false);

    // Continuation here
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    obj.Name = "Sally"; // <-- same obj here
    return obj;
}

public class SomeObject { public string Name; }

ConfigureAwait(false)似乎意味着 将继续编组回捕获的原始上下文- 好的,但这到底意味着什么?我已经尝试了上面的代码并且被obj 正确地引用回来(即使它在不同的线程上恢复)。

所以“上下文”似乎不是线程的工作内存(即线程本地存储)。那么“上下文”包含什么?因此,真正意味着什么

将延续编组回捕获的原始上下文

4

2 回答 2

7

正如我在async介绍性博客文章中所描述的,“上下文”是:

  • SynchronizationContext.Current, 除非是null, 在这种情况下
  • TaskScheduler.Current. 注意,如果当前没有任务调度器,则TaskScheduler.Current与 相同TaskScheduler.Default,是线程池上下文。

大多数情况下,这要么是 UI 或 ASP.NET 请求上下文(两种类型SynchronizationContext),要么是线程池上下文。任务调度程序上下文很少发挥作用。

请注意,此上下文仅用于安排 continuation。它对编组没有任何作用;在您的示例obj中,就像从 lambda 表达式引用它一样被捕获。

于 2015-03-25T23:01:59.420 回答
7

如果我没有完全错,ConfigureAwait(false);仅意味着在您等待的代码之后运行的代码不需要SynchronizationContext在等待之前使用 from 。

SynchronizationContext正如斯蒂芬指出的那样,可能是不同的事情。因此,假设您在 Web 环境中,并且等待之后的代码依赖于 HttpContext.Current.Items,如果您设置,这可能不再起作用ConfigureAwait(false);

例如,MVC 控制器中的以下代码将引发异常

    public async Task<ActionResult> Index()
    {
        System.Web.HttpContext.Current.Items["test"] = "test";

        var result = await SomethingAsync();

        return View();
    }

    private async Task<object> SomethingAsync()
    {
        await Task.Delay(1000).ConfigureAwait(false);

        // this will throw a nullpointer if ConfigureAwait is set to false
        return System.Web.HttpContext.Current.Items["test"];
    }

您的变量虽然只是在方法的范围内,因此它将可用,基本上是方法闭包/范围,如果这有意义吗?

于 2015-03-25T23:17:29.453 回答