【问题标题】:async void event handlers - clarification?async void 事件处理程序 - 澄清?
【发布时间】:2014-06-17 20:28:56
【问题描述】:

我正在尝试理解 为什么 这样做不好的原因:(注意,这里的上下文是 asp.net,不管async void 不可能的简单原因跟踪)

 public async void Page_Load(object sender, EventArgs e)
{
 ...
}

好吧,经过一番调查,我发现了几个不同的原因:

  • Damian Edwards 说 here 说:

    Web 表单中的异步 void 事件处理程序仅在某些设备上受支持 事件,正如您所发现的,但实际上仅用于简单化 任务。我们建议将 PageAsyncTask 用于任何真实的异步工作 复杂性。

  • Levi 说 here 说:

    Web 应用程序中的异步事件本质上是奇怪的野兽。异步 void 是一种“一劳永逸”的编程模型。这适用于 Windows UI 应用程序,因为该应用程序一直存在,直到 操作系统会杀死它,因此只要异步回调运行,就可以保证 成为可以与之交互的 UI 线程。在 Web 应用程序中,这 模型分崩离析,因为根据定义,请求是瞬态的。 如果 异步回调恰好在请求完成后运行,有 不保证回调需要交互的数据结构 与仍处于良好状态。因此,为什么一发不可收拾(和异步 void) 在 Web 应用程序中本质上是一个坏主意。

    也就是说,我们做疯狂的体操是为了尝试做一些非常简单的事情 喜欢 Page_Load 工作,但支持这一点的代码非常 复杂且未针对基本场景之外的任何内容进行良好测试。 因此,如果您需要可靠性,我会坚持使用 RegisterAsyncTask。

  • This site 说:

    众所周知 我们的页面生命周期有一组事件,这些事件在 预定义的顺序只有在最后一个事件发生时才会触发下一个事件 完成。所以如果我们使用上面的异步Page_Load方式,这个事件 一旦达到异步,将在页面生命周期事件中触发, 当前线程被释放,另一个线程被分配完成 任务异步执行,但 ASP.NET 无法执行下一个事件 在生命周期中,因为 Page_Load 尚未完成。和 底层同步上下文等到异步 活动完成。那么只有页面生命周期的下一个事件将是 触发,这使得整个过程仅处于同步模式。

  • This 网站说

    当返回类型为 void 时, 调用者可能会假设该方法在返回时已经完成。 这个问题可能会以许多意想不到的方式出现。通常是错误的 提供返回 void 的异步实现(或覆盖) 接口(或基类)上的方法。 有些事件还假设 它们的处理程序在返回时已完成

我在这里看到非常不同(不重叠)的原因。

问题:

什么是我们不应该写public async void Page_Load(object sender, EventArgs e)的荣耀/真正原因?


nb,我也不知道为什么这是个问题,因为 4.5 确实使用了 UseTaskFriendlySynchronizationContext,它的 aim is to support

protected async void Page_Load(object sender, EventArgs e){...}

【问题讨论】:

  • 注意所有与 ASP 相关的链接都说没关系,所有非 ASP 相关的链接都说你应该非常小心你如何使用async void。这应该告诉你一些事情,ASP 很特别。如果您阅读自己的一些链接,它们甚至会解释为什么 ASP 如此特别,以及它是如何让async void 方法按您希望的方式工作的;当然,这仅适用于简单的情况;它还解释了它什么时候不起作用,以及接下来该怎么做。
  • @Servy Levi 和 Damian 在 asp.net 开发中......所以我发现很难不相信他们......但另一方面......其他原因似乎也合法......所以......:-)

标签: c# asp.net async-await .net-4.5 c#-5.0


【解决方案1】:

您链接的文章很清楚地说明了原因。不要使用它,因为它在最基本的场景之外不可靠。我们只能在异步 void 方法上引入同步上下文中的异步跟踪技巧。我们确实努力使这些基本场景工作,但我们的一般指导是避免使用它们,而是显式注册异步工作。

【讨论】:

  • 您好 Damian,为了“避免异步无效”,我在 Page_Load 事件处理程序期间使用了 RegisterAsyncTask,但我无法获取任何数据以绑定到 Telerik RadGrid。方法都被调用并返回数据,但是数据绑定失败。您能帮我了解可能出了什么问题吗?
【解决方案2】:

我还没有验证这一点,但我认为在 ASP.NET 4.5 WebForms 中使用 async void Page_Load(...) 是可以的,只要页面有 <%@ Page Async="true" ... %> 声明即可。

我认为是基于implementation of AspNetSynchronizationContext.OperationStarted,当在带有AspNetSynchronizationContext 的线程上调用任何async void 方法时调用它。以下是相关评论:

 // If the caller tries to kick off an asynchronous operation while we are not
 // processing an async module, handler, or Page, we should prohibit the operation.

显然,带有Async="true" 的页面不违反此要求,并且在所有待处理的操作(包括async void 的操作)完成之前,HTTP 请求处理不会完成。

【讨论】:

    猜你喜欢
    • 2012-09-02
    • 1970-01-01
    • 2021-05-16
    • 1970-01-01
    • 2014-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多