【问题标题】:IIS hangs waiting for result of async call [duplicate]IIS 挂起等待异步调用的结果 [重复]
【发布时间】:2018-09-02 14:43:37
【问题描述】:

我们有一个运行由 IIS 编译的 C# 代码的 IIS 网站(这不是从 *.cs 文件运行的,它位于 aspx 页面上带有 <% %> 标记的代码中。没有使用 async 指令页面代码。我们有一个 .NET 库,其中包含一个公开异步方法的类。当我们尝试同步调用异步方法时,如下所示:

var articles = _cmsClient.GetAllArticlesAsync().Result;

页面无限期挂起。我们通过反复试验找到的解决方案是将异步调用包装在一个任务中:

List<Article> articles = null;
var wpLoadTask = Task.Run(async () =>
{
    articles = await _cmsClient.GetAllArticlesAsync();
});

wpLoadTask.Wait();

这是有效的,但我很想知道为什么。

【问题讨论】:

  • bing.com/search?q=c%23+async+result+deadlock 如果一个解释还不够。请注意,您的代码仍会导致死锁,只是在比.Result 的标准死锁更具体的情况下。
  • @AlexeiLevenkov 这看起来像是根本原因,但这段代码没有遇到死锁(我们不是在谈论死锁,不是线程饥饿)。 Task.Run 不会创建一个新的线程上下文,允许生成一个新线程以完成吗?如果没有,这是如何工作的?

标签: c# asp.net webforms async-await


【解决方案1】:

您不应从代码呈现块 (&lt;% %&gt;) 中调用异步方法,因为无法以异步方式进行该调用。换句话说,不存在诸如&lt;async% %&gt; 之类的语法或类似的语法。

相反,在@Page 指令中设置Async="true",将您的异步代码移动到代码隐藏方法,并在Page_Load 中使用RegisterAsyncTask 注册它。这一切都在示例in the documentation here 中进行了详细描述。

您在代码隐藏中放置的方法应该是这样的:

public async Task<List<Article>> GetAllArticlesAsync()
{
    var articles = await _cmsClient.GetAllArticlesAsync();
    return articles;
}
  • 不要使用.Result.Wait()。这些是阻塞的、非异步的方法。

  • 不要在 Task.Run 中换行 - 这只是将一项任务交换为另一项任务 - 这对于具有 UI 线程的桌面应用程序有效,但几乎没有理由用于 Web 应用程序。

【讨论】:

  • 明确地说,我不建议将其作为 ASP.NET 代码的模式 - 这是一个遗留网站,并且有大量技术债务阻碍了使该网站符合标准教科书 ASP.NET。很明显,使用 Task.Run 不仅仅是将一项任务交换为另一项任务,因为它允许调用成功。允许执行异步调用的衍生线程的线程上下文存在一些差异。
  • @PaulKeister 和 Task.Run 你可能会在你的 dev box 上与死掉的生产服务器上的挂起站点进行交易,因为它在咀嚼所有工作线程时得到了不错的负载。
  • @AlexeiLevenkov 毫无疑问这是真的,这就是我试图理解这种行为的原因。 Task.Run 解决方法增加了线程饥饿的可能性,如果有人有其他选择,而不是重写与此调用相关的所有代码以符合标准异步模式,我正在听。除了避免 Task.Run 的实践必要性之外,我还想更好地理解底层机制,具体来说:为什么 Thread.Run() 工作而 task.Wait() 挂起?
  • @PaulKeister 从链接副本中阅读了 Stephen Cleary 的文章。摘要:这两种情况都需要空闲的工作线程(来自线程池)来运行/完成,.Result(没有.ConfigureAwiat)死锁,因为它必须使用它启动的相同线程在; Task.Run 由于内部 await 而没有可用的工作线程开始操作或返回时死锁。请注意,Task.Run 不是“创建新线程”(搜索“C# 任务与线程”)。
  • @AlexeiLevenkov 感谢您的指导,链接的文章确实提供了解释,即 Task.Run 的 SynchronizationContext 没有捕获当前上下文(这需要一些推断,因为没有解释这种情况直接地)。除了错误之外,您坚持认为线程饥饿和死锁是相同的,这让我感到困惑。但无论如何,我祝你一切顺利。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-06
  • 2018-04-28
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 2016-12-20
  • 2018-09-22
相关资源
最近更新 更多