让我们看看一些简单的C#async / await代码,其中obj
之前和之后有一个对象引用(await
)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; }
ConfigureAwait(false)
似乎意味着不 将续集编组回到原始上下文 - 确定,但这究竟意味着什么?我已经尝试了上面的代码并正确引用了obj
IS (即使它在不同的线程上恢复)。
所以&#34; context&#34;它似乎不是线程的工作内存(即线程本地存储)。那么&#34; context&#34;包含?因此,
真正意味着什么将续集编组回原始上下文
答案 0 :(得分:6)
正如我在async
intro blog post中描述的那样,#34;背景&#34;是:
SynchronizationContext.Current
,除非它是null
,在这种情况下是TaskScheduler.Current
。请注意,如果没有当前任务调度程序,则TaskScheduler.Current
与TaskScheduler.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"];
}
你的变量只是在方法的范围内,因此它是可用的,基本上是方法闭包/范围,如果这是有道理的吗?