Dee*_*101 22 c# multithreading asynchronous synchronizationcontext
让我们看看一些简单的C#async/await代码,其中我obj
在await
with 之前和之后有一个对象引用()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正确引用了(即使它在不同的线程上恢复).
所以"上下文"似乎不是线程的工作内存(即线程本地存储).那么"上下文"包含什么?因此,它到底意味着什么
将继续编组回到捕获的原始上下文
如果我不是完全错误,则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)
您的变量虽然只是在方法的范围内,因此它将可用,基本上是方法闭包/范围,如果这有意义吗?
正如我在我的async
介绍博客文章中描述的那样,"上下文"是:
SynchronizationContext.Current
,除非是null
,在这种情况下是TaskScheduler.Current
.请注意,如果没有当前的任务调度程序,那么TaskScheduler.Current
它是相同的TaskScheduler.Default
,这是一个线程池上下文.绝大多数情况下,这是UI或ASP.NET请求上下文(两种类型SynchronizationContext
),或者它是线程池上下文.任务调度程序上下文很少发挥作用.
请注意,此上下文仅用于计划延续.它对编组没有任何作用; 在您的示例obj
中捕获就像从lambda表达式引用它一样.