“上下文”在C#async / await代码中的确切含义是什么?

时间:2015-03-25 22:51:40

标签: c# multithreading asynchronous synchronizationcontext

让我们看看一些简单的C#async / await代码,其中obj之前和之后有一个对象引用(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 IS (即使它在不同的线程上恢复)。

所以&#34; context&#34;它似乎不是线程的工作内存(即线程本地存储)。那么&#34; context&#34;包含?因此,

真正意味着什么
  

将续集编组回原始上下文

2 个答案:

答案 0 :(得分:6)

正如我在async intro blog post中描述的那样,#34;背景&#34;是:

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

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

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

答案 1 :(得分:3)

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

斯蒂芬指出,

SynchronizationContext可能是不同的东西。因此,假设您处于Web环境中,并且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"];
    }

你的变量只是在方法的范围内,因此它是可用的,基本上是方法闭包/范围,如果这是有道理的吗?