繁体   English   中英

ASP.NET异步任务执行序列

[英]ASP.NET async task execution sequence

我只是在asp.net上遇到并发编码,发现在Page_Load方法中有两种触发异步方法的方法

  1. RegisterAsyncTask(new PageAsyncTask(DoSthAsync()));
  2. 等待DoSthAsync();

但是,它们具有不同的运算结果。 对于情况1, RegisterAsyncTask之后的代码将立即在DoSthAsync()中的任何代码之前运行。 等待后的代码将在DoSthAsync()完成时运行。

例如:

//protected async void Page_Load(object sender, EventArgs e)
protected void Page_Load(object sender, EventArgs e)
{    
    Response.Write("Start</br>");
    Response.Flush();
    RegisterAsyncTask(new PageAsyncTask(DoSthAsync()));
    //await DoSthAsync();
    Response.Write("End</br>");
    Response.Flush();
}

public async Task LoadSomeData()
{
    await Task.Delay(1000);
    Response.Write("Do Sth Async</br>");
    Response.Flush();
}

此代码段将产生以下结果:

Start
End
Do Sth Async  *(after 1 second delay)*

当我取消注释等待DoSthAsync()代码并注释RegisterAsyncTask时 ,将显示以下结果。

Start
Do Sth Async  *(after 1 second delay)*
End

在Rick Anderson的文章“ 在ASP.NET 4.5中使用异步方法”中 ,他建议使用RegisterAsyncTask可以更好地控制代码执行。 但是,这给出了意外的结果,我在page_load中等待时正在寻找的结果将与在Windows程序中尝试类似的代码序列时生成相同的结果。

在他的文章中,Rick还具有Stopwatch的代码,该代码在GetPWGsrvAsync()触发之前开始,在所有异步代码完成后停止,以显示代码执行了多长时间后停止。 它显示的屏幕时间为0.872s。 因此,预期秒表将在所有先前的代码(包括异步方法中的所有代码)完成后停止。

.......
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
RegisterAsyncTask(new PageAsyncTask(DoSthAsync()));
//await DoSthAsync();
stopWatch.Stop();
Response.Write(String.Format("Elapsed time:{0}",stopWatch.Elapsed.Milliseconds / 1000.0));
Response.Write("</br>");
Response.Flush();
.......

尽管我像上面的代码片段一样使用它,但是在RegisterAsyncTaskawait DoSthAsync()中却得到了不同的结果。 尽管经过时间显示在不同的位置,但它们都给我很短的经过时间,大约为0.010s或10 + ms,并且可以相信,在触发异步函数DoSthAsync()之后,秒表很快就停止了。 实际上,在窗口程序中也有类似的结果,它很快就停止了。

详细描述问题之后,我想问一下异步编码的哪种方式具有更好的控制和代码模式。 在两者之间,我如何期望秒表的结果给我准确的代码经过时间。

页面异步任务早在async-await之前就已经存在。

页面异步任务是关于在请求生命周期中执行异步任务(不一定是Task )。

async-await是关于具有异步方法和异步操作的。

如果在Page_Load使用async-await ,因为它是一个返回void方法,那么运行时将无法知道该方法是异步的,以及其异步工作是否完成。

看一下PageAsyncTask的文档 ,看看最适合您的需求。 但是您应该认真看一下页面异步任务。

首先, Stopwatch在两种情况下都返回如此短的时间,因为您使用了错误的属性。 stopWatch.Elapsed.Milliseconds只会向您返回所测量间隔的最后一秒中的毫秒数。 您想要的是stopWatch.ElapsedMilliseconds因为这将返回测量期间经过的毫秒总数。 这将为您提供两种使用方法之间的巨大差异。

await DoSthAsync(); 执行时间将超过一秒。 这是由于await关键字的基本含义是:等待异步操作成功完成,然后再执行下面的代码。 这样可以确保您至少在这种情况下以同步方式运行代码,但是将长期运行的操作安排在ThreadPool线程中。 实际上,这确实可以满足您的要求,但是在void返回方法中仍然有使用async / await的缺点,这不是非法的,但我会避免这样做。 您可以在此处阅读其缺点的所有内容。

使用RegisterAsyncTaskPageAsyncTask的第二种方法的执行时间将小于1秒。 这是因为它只注册要执行的任务,然后立即返回以处理下面的代码。 由于您的代码是在Page_Load事件中编写的,因此长时间运行的操作将仅在PreRenderComplete事件完成后自动开始。 但是您可以使用Page.ExecuteRegisteredAsyncTasks();手动开始执行任务Page.ExecuteRegisteredAsyncTasks(); 但请注意:这也不会等待任务完成,而只会更早开始执行。

基本上,您还有两个选择来获得所需的结果:

  1. 使用您的第一种方法并忍受不利之处。
  2. 重构代码,以便可以通过使用包含EventHandlers的PageAsyncTask的另一个构造函数来使用第二种方法。 您可以使用这些EventHandlers执行应在异步任务完成后运行的代码。 您可以在这里找到这种方法的一个很好的例子。

您将如何处理此信息。 请注意,我强烈建议您使用选项2。

暂无
暂无

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

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