我刚刚在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的文章Using Asynchronous Methods in ASP.NET 4.5中,他建议使用 RegisterAsyncTask 可以更好地控制代码执行。但是,这给出了一个意想不到的结果,我正在寻找,而在Windows程序中尝试类似的代码序列时,page_load中的await将生成相同的结果。
在他的文章中,Rick还在GetPWGsrvAsync()之前启动了秒表启动代码,并在所有异步代码完成后停止显示代码执行了多长时间。它显示屏幕截图中的经过时间为0.872秒。因此,在所有先前的代码(包括所有异步方法完成)之后,它的预期秒表会停止。
.......
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.010秒或10 + ms并且它相信秒表在异步功能后很快停止触发了DoSthAsync()。事实上,在窗口程序中也有类似的结果,它很快停止了。
在对问题进行了长时间的描述之后,我想问一下异步编码的哪种方式可以获得更好的控制和代码模式。在这两者之间,我怎么能有预期的秒表结果给我确切的代码经过时间。
答案 0 :(得分:1)
页面异步任务早在async-await
之前就已存在。
页面异步任务是关于在请求生命周期中执行异步任务(不一定是Task
)。
async-await
是关于使用异步操作的异步方法。
如果在async-await
中使用Page_Load
,因为它是一个void
- 返回方法,运行时无法知道该方法是异步的,以及它的异步工作是否完成或不。
查看the documentation for PageAsyncTask
,了解最适合您需求的内容。但是你应该认真看看页面异步任务。
答案 1 :(得分:1)
首先要做的事情是:由于你使用了错误的属性,你的Stopwatch
在这两种情况下都会返回如此荒谬的短暂时间。 stopWatch.Elapsed.Milliseconds
只会返回测量的intervall最后一秒的毫秒数。您想要的是stopWatch.ElapsedMilliseconds
,因为这将返回测量期间经过的总毫秒数。这将为您提供两种使用方法之间的巨大差异。
await DoSthAsync();
的执行时间会略高于一秒。这是因为await
关键字基本上意味着:等到异步操作成功完成后才执行下面的代码。这可以保证至少在此上下文中代码以同步样式运行,但是长时间运行操作的执行被调度到ThreadPool线程。这实际上做了你想要的,但仍然有一个在void
返回方法中使用async / await的缺点,这不是非法的,但我不会这样做。你可以阅读它的缺点here。
使用RegisterAsyncTask
和PageAsyncTask
的第二种方法的执行时间低于1秒。这是因为它只是将任务注册为执行并立即返回以处理下面的代码。由于您的代码是在Page_Load
事件中编写的,因此长时间运行操作的执行只会在PreRenderComplete
事件完成后自动启动。但您可以使用Page.ExecuteRegisteredAsyncTasks();
手动开始执行任务。但请注意:这也不会等待任务完成,只是提前开始执行。
基本上你还有两个选择来获得你想要的结果:
您将对此信息做些什么取决于您。请注意,我强烈建议您使用选项2。