异步无返回值事件处理程序 - 澄清?

7
我试图理解为什么这样做是不好的:(请注意,此处上下文是asp.net,而不管async void不能被追踪的简单原因)
 public async void Page_Load(object sender, EventArgs e)
{
 ...
}

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

  • Damian Edwards在这里表示:Web Forms中的异步void事件处理程序仅支持某些事件,但实际上只适用于简单任务。我们建议对任何真正复杂的异步工作使用PageAsyncTask。

  • Levi在这里表示: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){...}


请注意,所有与ASP相关的链接都说可以使用async void,而所有与非ASP相关的链接都说你应该非常小心。这应该告诉你一些事情,即ASP很特殊。如果你阅读一些自己的链接,它们甚至会解释为什么ASP很特殊,以及它是如何允许async void方法按照你所希望的方式工作的;当然,这仅适用于简单的情况;它还解释了什么情况下它不起作用以及该怎么做。 - Servy
@Servy,Levi和Damian都从事asp.net开发...所以我很难不相信他们...但另一方面,其他原因似乎也是合理的...所以... :-) - Royi Namir
2个回答

5
您链接的文章已经很清楚地解释了原因。不要使用它,因为除了最基本的情况外,它是不可靠的。在异步void方法的同步上下文中,我们只能进行有限的异步跟踪技巧。我们确实努力让这些基本场景正常工作,但我们的一般建议是避免使用它们,而是显式注册异步工作。

你好,Damian。为了“避免异步void”,我在Page_Load事件处理程序中使用了RegisterAsyncTask,但是我无法获取任何数据来绑定到Telerik RadGrid。所有方法都被调用并返回数据,但数据绑定失败了。 你能帮我理解可能出了什么问题吗? - Pramod Mangalore

2

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

我基于AspNetSynchronizationContext.OperationStarted的实现,当任何async void方法在带有AspNetSynchronizationContext的线程上调用时,它会被调用。这里有一个相关的注释:

 // 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" 的页面不违反此要求,并且HTTP请求处理不会在所有待处理操作完成之前完成,包括 async void 操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接