C# · 12月 29, 2021

c# – 即使在Asp.Net流中使用ConfigureAwait(false)后仍然死锁

即使在使用ConfigureAwait(false)之后,我也遇到死锁,下面是示例代码.

根据样本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.