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

Dee*_*101 22 c# multithreading asynchronous synchronizationcontext

让我们看看一些简单的C#async/await代码,其中我objawaitwith 之前和之后有一个对象引用()ConfigureAwait(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; }
Run Code Online (Sandbox Code Playgroud)

ConfigureAwait(false)似乎意味着没有 将延续回到原始上下文 - 好吧,但这究竟意味着什么?我已经尝试了上面的代码并且obj IS正确引用了(即使它在不同的线程上恢复).

所以"上下文"似乎不是线程的工作内存(即线程本地存储).那么"上下文"包含什么?因此,它到底意味着什么

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

Mic*_*haC 7

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

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"];
    }
Run Code Online (Sandbox Code Playgroud)

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

  • *“在您等待的代码之后运行的代码不能在同一个 SynchronizationContext 中运行。”* 不正确。更好的说法是*“在您等待的代码之后运行的代码,不需要使用等待之前的 SynchronizationContext”*。如果您等待处于已完成状态的任务,您可能仍会使用与等待之前相同的上下文,因为代码将同步获取结果并且永远不会返回给调用者。 (2认同)

Ste*_*ary 6

正如我在我的async介绍博客文章中描述的那样,"上下文"是:

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

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

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

  • @ DeepSpace101这意味着它调用[`SynchronizationContext.Send`](https://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.send(v = vs.110).aspx)或[` SynchronizationContext.Post`](https://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.post(v = vs.110).aspx)与continuation delagate.它是如何处理该委托的上下文的实现(对于单线程的(WPF和Winforms),它将它放入要处理的消息队列中,用于基于池的(ASP.net和线程)池)它从池中获取资源. (3认同)