简体   繁体   English

async void事件处理程序 - 澄清?

[英]async void event handlers - clarification?

I'm trying to understand the reason why is it bad to do: (notice, context here is asp.net, regardless the plain reason that async void can't be tracked) 我试图理解为什么不好做的原因:( 注意,这里的上下文是asp.net,无论是否无法跟踪async void原因)

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

Well , after investigating a bit I saw few different reasons : 好吧,经过调查,我看到几个不同的原因:

  • Damian Edwards Says here that: 达米安·爱德华兹在这里说:

    Async void event handlers in web forms are only supported on certain events , as you've found, but are really only intended for simplistic tasks. Web表单中的异步void事件处理程序仅在某些事件上受支持 ,如您所见,但实际上仅用于简单的任务。 We recommend using PageAsyncTask for any async work of any real complexity. 我们建议使用PageAsyncTask进行任何真正复杂的异步工作。

  • Levi Says here that: 列维在这里说:

    Async events in web applications are inherently strange beasts. Web应用程序中的异步事件本质上就是奇怪的怪物。 Async void is meant for a fire and forget programming model. Async void适用于火灾和忘记编程模型。 This works in Windows UI applications since the application sticks around until the OS kills it, so whenever the async callback runs there is guaranteed to be a UI thread that it can interact with. 这适用于Windows UI应用程序,因为应用程序一直存在,直到操作系统将其杀死,因此每当异步回调运行时,都保证它是可以与之交互的UI线程。 In web applications, this model falls apart since requests are by definition transient. 在Web应用程序中,由于请求是按定义瞬态的,因此该模型会崩溃。 If the async callback happens to run after the request has finished, there is no guarantee that the data structures the callback needs to interact with are still in a good state . 如果异步回调恰好在请求完成后运行,则无法保证回调需要与之交互的数据结构仍处于良好状态 Thus why fire and forget (and async void) is inherently a bad idea in web applications. 因此,为什么火灾和遗忘(以及异步无效)在Web应用程序中本身就是一个坏主意。

    That said, we do crazy gymnastics to try to make very simple things like Page_Load work, but the code to support this is extremely complicated and not well-tested for anything beyond basic scenarios. 也就是说,我们做疯狂的体操试图制作非常简单的东西,如Page_Load工作,但支持这一点的代码非常复杂,并且没有经过基本场景之外的任何测试。 So if you need reliability I'd stick with RegisterAsyncTask. 因此,如果您需要可靠性,我会坚持使用RegisterAsyncTask。

  • This site says: 这个网站说:

    As we know our page life cycle has a set of events that gets fired in a predefined order and next event will be fired only when the last event completes. 我们知道我们的页面生命周期有一组事件以预定义的顺序触发,下一个事件只有在最后一个事件完成时才会触发。 So if we use the above way of async Page_Load, this event will be fired during page life cycle event once it reaches to async, current thread gets free and a another thread got assigned to complete the task asynchronously, but the ASP.NET cannot execute the next event in life cycle because Page_Load has not been completed yet . 因此,如果我们使用上述异步Page_Load方式,则在页面生命周期事件中,一旦它到达异步,当前线程被释放并且另一个线程被分配以异步完成任务,此事件将被触发, 但ASP.NET无法执行生命周期中的下一个事件,因为Page_Load尚未完成 And underlying synchronization context waits till the asynchronous activity completes. 底层同步上下文等待,直到异步活动完成。 Then only the next event of page lifecycle will be fired which makes the whole process in synchronous mode only. 然后,只会触发页面生命周期的下一个事件,这使得整个过程仅处于同步模式。

  • This site says 这个网站说

    when the return type is void, the caller might assume the method is complete by the time it returns . 当返回类型为void时,调用者可能会认为该方法在返回时已完成 This problem can crop up in many unexpected ways. 这个问题可能以许多意想不到的方式出现。 It's usually wrong to provide an async implementation (or override) of a void-returning method on an interface (or base class). 在接口(或基类)上提供void返回方法的异步实现(或覆盖)通常是错误的。 Some events also assume that their handlers are complete when they return . 有些事件还假设他们的处理程序在返回时是完整的

I see here very different (non-overlapping) reasons. 我在这里看到非常不同 (非重叠)的原因。

Question : 题 :

What is the glory/true reason for which we shouldn't write public async void Page_Load(object sender, EventArgs e) ? 什么是我们不应该写public async void Page_Load(object sender, EventArgs e)的荣耀/真正的原因public async void Page_Load(object sender, EventArgs e)


nb, I also don't know why it is a problem since 4.5 does use the UseTaskFriendlySynchronizationContext which its aim is to support : 嗯,我也不知道为什么它是一个问题,因为4.5确实使用了其目的是支持UseTaskFriendlySynchronizationContext

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

The articles you link to make the reasons pretty clear. 您链接的文章使原因非常清楚。 Don't use it because it isn't reliable beyond the most basic of scenarios. 不要使用它,因为除了最基本的场景之外它不可靠。 There is only so much async tracking trickery we can pull in the synchronization context on async void methods. 我们可以在异步void方法中引入同步上下文,只有很多异步跟踪技巧。 We did work to make those basic scenarios work, but our general guidance is to avoid using them and instead explicitly register async work. 我们确实努力使这些基本方案工作,但我们的一般指导是避免使用它们,而是明确地注册异步工作。

I haven't verified this , but I think it's OK to use async void Page_Load(...) in ASP.NET 4.5 WebForms, for as long as the page has <%@ Page Async="true" ... %> declaration. 我还没有验证这一点 ,但我认为只要页面有<%@ Page Async="true" ... %> ,就可以在ASP.NET 4.5 WebForms中使用async void Page_Load(...) <%@ Page Async="true" ... %>宣言。

I think so based on the implementation of AspNetSynchronizationContext.OperationStarted , which is called when any async void method is invoked on a thread with AspNetSynchronizationContext . 我认为这是基于AspNetSynchronizationContext.OperationStarted实现,当在具有AspNetSynchronizationContext的线程上调用任何async void方法时调用AspNetSynchronizationContext Here's a relevant comment: 以下是相关评论:

 // 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.

Apparently, pages with Async="true" do not violate this requirement, and the HTTP request processing isn't going to be completed until all pending operations have completed, including async void ones. 显然, Async="true"页面不违反此要求,并且在完成所有挂起操作(包括async void操作)之前,不会完成HTTP请求处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM