根据样本http://blog.stephencleary.com/2012/02/async-and-await.html(#Avoding上下文),这不应该是死锁.
这是我的课:
public class ProjectsRetriever { public string GetProjects() { ... var projects = this.GetProjects(uri).Result; ... ... } private async Task<IEnumerable<Project>> GetProjects(Uri uri) { return await this.projectSystem.GetProjects(uri,Constants.UserName).ConfigureAwait(false); } }
这个类来自一个共享库:
public class ProjectSystem { public async Task<IEnumerable<Project>> GetProjects(Uri uri,string userName) { var projectClient = this.GetHttpClient<ProjectHttpClient>(uri); var projects = await projectClient.GetProjects(); // code here is never hit ... }
如果我在配置HttpClient调用的共享库中添加ConfigureAwait(false)来等待调用,则可以工作:
public class ProjectSystem { public async Task<IEnumerable<Project>> GetProjects(Uri uri,string userName) { var projectClient = this.GetHttpClient<ProjectHttpClient>(uri); var projects = await projectClient.GetProjects().ConfigureAwait(false); // no deadlock,resumes in a new thread. ... }
我一直在浏览所有发现的博客,只有区别我发现ConfigureAwait(false)工作时使用httpClient.AsyncApi()调用!
请帮忙澄清!!!
解决方法
I was under assumption,once ConfigureAwait(false) is used (any where in the call stack),execution from that point will not cause deadlock.
我不相信黑魔法,也不应该.始终努力了解当您在代码中使用某些内容时会发生什么.
当等待返回任务或任务< T>的异步方法时,Task.GetAwaiter方法生成的TaskAwaitable将隐含捕获SynchronizationContext.
一旦同步上下文到位并且异步方法调用完成,TaskAwaitable会尝试将继承(其基本上是第一个await关键字之后的其余方法调用)编组到先前捕获的SynchronizationContext(使用SynchronizationContext.Post) .如果调用线程被阻止,等待同一个方法完成,你有一个死锁.
你应该问自己Should I expose synchronous wrappers for asynchronous methods? 99%的答案是否定的.您应该使用同步API,例如WebClient提供的API.