[英]ASP.NET async task execution sequence
I just come across concurrency coding on asp.net and found there is 2 ways to trigger an async method at Page_Load method 我只是在asp.net上遇到并发编码,发现在Page_Load方法中有两种触发异步方法的方法
However, they have different operation result. 但是,它们具有不同的运算结果。 For the case 1, the code right after RegisterAsyncTask will run immediately before any code in DoSthAsync().
对于情况1, RegisterAsyncTask之后的代码将立即在DoSthAsync()中的任何代码之前运行。 While the code after await will run at completion of DoSthAsync().
而等待后的代码将在DoSthAsync()完成时运行。
Eg: 例如:
//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();
}
This code snippet will generate the following result: 此代码段将产生以下结果:
Start
End
Do Sth Async *(after 1 second delay)*
While I uncomment await DoSthAsync() code and comment RegisterAsyncTask , the following result will be shown. 当我取消注释等待DoSthAsync()代码并注释RegisterAsyncTask时 ,将显示以下结果。
Start
Do Sth Async *(after 1 second delay)*
End
In Rick Anderson's article Using Asynchronous Methods in ASP.NET 4.5 , he suggested using RegisterAsyncTask will give a better control on code execution. 在Rick Anderson的文章“ 在ASP.NET 4.5中使用异步方法”中 ,他建议使用RegisterAsyncTask可以更好地控制代码执行。 However, this gives an unexpected result which I'm looking for while await in page_load will generate identical one as I try the similar code sequence in windows program.
但是,这给出了意外的结果,我在page_load中等待时正在寻找的结果将与在Windows程序中尝试类似的代码序列时生成相同的结果。
In his article, Rick also has code of Stopwatch start before GetPWGsrvAsync() fired and stop after all async code completed showing how long the code executed. 在他的文章中,Rick还具有Stopwatch的代码,该代码在GetPWGsrvAsync()触发之前开始,在所有异步代码完成后停止,以显示代码执行了多长时间后停止。 It shows elapsed time is 0.872s in the screen cap.
它显示的屏幕时间为0.872s。 Therefore it's expected stopwatch is stopped after all previous code including all in async method completed.
因此,预期秒表将在所有先前的代码(包括异步方法中的所有代码)完成后停止。
.......
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();
.......
While I follow it the same way like the code snippet above, I have different result in either RegisterAsyncTask or await DoSthAsync() . 尽管我像上面的代码片段一样使用它,但是在RegisterAsyncTask或await DoSthAsync()中却得到了不同的结果。 Although the Elapsed time displayed at different position, they both give me very short elapsed time about 0.010s or 10+ms and it's believe the stopwatch is stopped very shortly after async function DoSthAsync() is fired.
尽管经过时间显示在不同的位置,但它们都给我很短的经过时间,大约为0.010s或10 + ms,并且可以相信,在触发异步函数DoSthAsync()之后,秒表很快就停止了。 In fact, similar result in window program too, it stopped very soon.
实际上,在窗口程序中也有类似的结果,它很快就停止了。
After long description of the problem, I would like to ask which way of async coding to have better control and code pattern. 详细描述问题之后,我想问一下异步编码的哪种方式具有更好的控制和代码模式。 In between, how can I have expected result of stopwatch to give me exact code elapsed time.
在两者之间,我如何期望秒表的结果给我准确的代码经过时间。
Page async tasks have been around since long before async-await
. 页面异步任务早在
async-await
之前就已经存在。
Page async tasks are about executing asynchronous tasks (not necessarily Task
s) in the request lifecycle. 页面异步任务是关于在请求生命周期中执行异步任务(不一定是
Task
)。
async-await
is about having asynchronous methods with asynchronous operations. async-await
是关于具有异步方法和异步操作的。
If you use async-await
in Page_Load
, because it is a void
-returning method, the runtime has no way to know that the method is asynchronous and if its asynchronous work is done or not. 如果在
Page_Load
使用async-await
,因为它是一个返回void
方法,那么运行时将无法知道该方法是异步的,以及其异步工作是否完成。
Have a look at the documentation for PageAsyncTask
and see what best suits your needs. 看一下
PageAsyncTask
的文档 ,看看最适合您的需求。 But you should have a serious look at page async tasks. 但是您应该认真看一下页面异步任务。
First things first: your Stopwatch
returns such ridiculously short amounts of time in both cases since you use the wrong property. 首先,
Stopwatch
在两种情况下都返回如此短的时间,因为您使用了错误的属性。 stopWatch.Elapsed.Milliseconds
will just return you the amount of milliseconds in the last second of the measured intervall. stopWatch.Elapsed.Milliseconds
只会向您返回所测量间隔的最后一秒中的毫秒数。 What you wanted is stopWatch.ElapsedMilliseconds
since this would return the total amount of milliseconds which elapsed during the measurement. 您想要的是
stopWatch.ElapsedMilliseconds
因为这将返回测量期间经过的毫秒总数。 And this will provide you with great differences between the two used methods. 这将为您提供两种使用方法之间的巨大差异。
The await DoSthAsync();
await DoSthAsync();
will have an execution time of a little bit above one second. 执行时间将超过一秒。 This is due to the fact that the
await
keyword basically means: wait until the asynchronous operation is finished successful and only afterwards execute the code below. 这是由于
await
关键字的基本含义是:等待异步操作成功完成,然后再执行下面的代码。 This guarantees you that at least in this context the code is run in a synchronous style but the execution of the long running operation is scheduled to a ThreadPool thread. 这样可以确保您至少在这种情况下以同步方式运行代码,但是将长期运行的操作安排在ThreadPool线程中。 This in fact does what you want but still has the downside of using async/await in a
void
returning method which is not illegal but I'd refrain from it. 实际上,这确实可以满足您的要求,但是在
void
返回方法中仍然有使用async / await的缺点,这不是非法的,但我会避免这样做。 You can read everything on the downsides of it here . 您可以在此处阅读其缺点的所有内容。
The second approach which uses RegisterAsyncTask
and PageAsyncTask
will have an execution time somewhere below 1 second. 使用
RegisterAsyncTask
和PageAsyncTask
的第二种方法的执行时间将小于1秒。 This is due to the fact that it simply registers the task for execution and immediately returns to process the code below. 这是因为它只注册要执行的任务,然后立即返回以处理下面的代码。 Since your code is written in the
Page_Load
event the execution of your long running operation will only start automatically after the PreRenderComplete
event has completed. 由于您的代码是在
Page_Load
事件中编写的,因此长时间运行的操作将仅在PreRenderComplete
事件完成后自动开始。 But you can start the execution of your task manually with Page.ExecuteRegisteredAsyncTasks();
但是您可以使用
Page.ExecuteRegisteredAsyncTasks();
手动开始执行任务Page.ExecuteRegisteredAsyncTasks();
. 。 But note: this also won't wait for the completion of your task and just start the execution earlier.
但请注意:这也不会等待任务完成,而只会更早开始执行。
Basically you have two options left to obtain the result that you desire: 基本上,您还有两个选择来获得所需的结果:
What you will do with this information is up to you. 您将如何处理此信息。 Just be reminded that I'd highly recommend using option 2 to you.
请注意,我强烈建议您使用选项2。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.