异步无效事件处理程序 - 说明
本文关键字:说明 程序 事件处理 无效 异步 | 更新日期: 2023-09-27 18:01:12
我试图理解为什么这样做不好的原因:(注意,这里的上下文是 asp.net,不管async void
无法跟踪的简单原因(
public async void Page_Load(object sender, EventArgs e)
{
...
}
好吧,经过一番调查,我看到了几个不同的原因:
达米安·爱德华兹在这里说:
Web 表单中的异步无效事件处理程序仅在某些窗体上受支持 事件,正如你所发现的,但实际上只是为了简单化 任务。我们建议将PageAsyncTask用于任何实际工作的任何异步工作 复杂性。
李维在这里说:
Web 应用程序中的异步事件本质上是奇怪的野兽。异步 void 用于一劳永逸的编程模型。这适用于 Windows UI应用程序,因为该应用程序一直存在,直到 操作系统会杀死它,因此每当异步回调运行时,都会保证 成为可以与之交互的 UI 线程。在 Web 应用程序中,这 模型分崩离析,因为根据定义,请求是暂时的。如果 异步回调碰巧在请求完成后运行,有 不保证回调需要交互的数据结构 与仍然处于良好状态。因此,为什么要开火并忘记(和异步 void( 在 Web 应用程序中本质上是一个坏主意。
也就是说,我们做疯狂的体操是为了尝试做非常简单的事情。 喜欢Page_Load工作,但支持此功能的代码非常 复杂且未针对基本方案以外的任何内容进行充分测试。 因此,如果您需要可靠性,我会坚持使用RegisterAsyncTask。
这个网站说:
众所周知 我们的页面生命周期有一组事件,这些事件在 预定义的顺序和下一个事件仅在最后一个事件时触发 完成。所以如果我们使用上面的异步Page_Load方式,这个事件 一旦达到异步,将在页面生命周期事件期间触发, 当前线程获得空闲,另一个线程被分配完成 异步任务,但 ASP.NET 无法执行下一个事件 在生命周期中,因为Page_Load尚未完成。和 基础同步上下文等到异步 活动完成。那么只有页面生命周期的下一个事件将是 触发,使整个过程仅处于同步模式。
这个网站说
当返回类型为 void 时,将 调用方可能会假定该方法在返回时已完成。 此问题可能会以许多意想不到的方式出现。通常是错误的 提供 void 返回的异步实现(或覆盖( 接口(或基类(上的方法。某些事件还假定 当他们返回时,他们的处理程序已完成。
我在这里看到非常不同(非重叠(的原因。
问题:
我们不应该写public async void Page_Load(object sender, EventArgs e)
的荣耀/真正原因是什么?
注意,我也不知道为什么这是一个问题,因为 4.5 确实使用了 UseTaskFriendlySynchronizationContext,其目的是支持:
protected async void Page_Load(object sender, EventArgs e){...}
您链接的文章可以清楚地说明原因。不要使用它,因为它在最基本的方案之外不可靠。我们可以在异步 void 方法的同步上下文中提取的异步跟踪技巧只有这么多。我们确实努力使这些基本方案正常工作,但我们的一般指导是避免使用它们,而是显式注册异步工作。
我还没有验证这一点,但我认为只要页面有<%@ Page Async="true" ... %>
声明,就可以在 4.5 WebForms ASP.NET 中使用async void Page_Load(...)
。
我认为是基于 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请求处理不会完成。