'context' 在 C# async/await 代码中的确切含义是什么?

What does 'context' exactly mean in C# async/await code?

让我们看一些简单的 C# async/await 代码,其中我在 awaitConfigureAwait(false)

之前和之后有一个对象引用 (obj)
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) 似乎意味着 NOT 将延续编组回捕获的原始上下文 - 好的,但是那是什么实际意思?我已经尝试了上面的代码并且 obj IS 正确地引用回来了(即使它在不同的线程上恢复)。

所以 "context" 似乎不是线程的工作内存(即线程本地存储)。那么 "context" 包含什么?因此,这对

到底意味着什么?

marshal the continuation back to the original context captured

如我在 async intro blog post 中所述,"context" 是:

  • SynchronizationContext.Current,除非是null,那样的话就是
  • TaskScheduler.Current。注意,如果没有current task scheduler,那么TaskScheduler.CurrentTaskScheduler.Default一样,都是线程池context。

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

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

如果我没有完全错的话,ConfigureAwait(false); 仅表示在 您正在等待的代码之后运行 的代码不需要使用 SynchronizationContext 从 await 之前开始。

正如斯蒂芬指出的那样,

SynchronizationContext 可能是不同的东西。所以想象一下你在一个网络环境中并且你的代码在 await 之后依赖于 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"];
    }

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