[英]ASP.NET async task execution sequence
我只是在asp.net上遇到并发编码,发现在Page_Load方法中有两种触发异步方法的方法
但是,它们具有不同的运算结果。 对于情况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();
.......
尽管我像上面的代码片段一样使用它,但是在RegisterAsyncTask或await 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的缺点,这不是非法的,但我会避免这样做。 您可以在此处阅读其缺点的所有内容。
使用RegisterAsyncTask
和PageAsyncTask
的第二种方法的执行时间将小于1秒。 这是因为它只注册要执行的任务,然后立即返回以处理下面的代码。 由于您的代码是在Page_Load
事件中编写的,因此长时间运行的操作将仅在PreRenderComplete
事件完成后自动开始。 但是您可以使用Page.ExecuteRegisteredAsyncTasks();
手动开始执行任务Page.ExecuteRegisteredAsyncTasks();
。 但请注意:这也不会等待任务完成,而只会更早开始执行。
基本上,您还有两个选择来获得所需的结果:
您将如何处理此信息。 请注意,我强烈建议您使用选项2。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.