2016-03-07 140 views
1

我只是遇到并发编码在asp.net,发现有2种方式来触发在Page_Load方法ASP.NET异步任务执行序列

  1. RegisterAsyncTask异步方法(新PageAsyncTask(DoSthAsync())) ;
  2. await 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 

在里克·安德森的文章Using Asynchronous Methods in ASP.NET 4.5,他建议使用RegisterAsyncTask会给代码执行的更好的控制。然而,这给了一个意想不到的结果,我期待在page_load等待将生成相同的一个,因为我尝试在Windows程序中的类似代码序列。

在他的文章中,里克也有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等待DoSthAsync()。虽然已用时间显示在不同的位置,但它们都给我非常短的运行时间约0.010s或10 + ms,并且它认为秒表异步功能DoSthAsync()被激发后很短时间停止。事实上,在窗口程序中也有类似的结果,它很快就停止了。

问题的长说明后,我想问一下异步编码哪种方式更好地控制和代码模式。在这之间,我怎么能期望秒表的结果给我精确的代码流逝时间。

回答

1

页的异步任务就已经存在了很久以前async-await

页异步任务是有关在请求生命周期执行异步任务(不一定Task多个)。

async-await是大约具有异步操作异步方法。

如果您使用Page_Loadasync-await,因为它是一个void -returning方法,运行时有没有办法知道该方法是异步的,如果它的异步工作完成与否。

看看the documentation for PageAsyncTask,看看最适合您的需求。但是你应该认真看待页面异步任务。

+0

我也建议你阅读以下文章由Scott Hanselmann关于这个主题:http://www.hanselman.com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx –

+0

@ManuelZelenka我也读过这篇文章,但它已经没有提及RegisterAsyncTask和await之间的区别。他只是提到了 “使用async with void并不稳定或可靠,但是您只需要调用Page.RegisterAyncTask - 这不会有任何问题,您将处于一个更加灵活的地方。”这与我提到的里克的文章是一样的。他的例子在Page_Load中只有一个动作。 – Donald

+0

是的,我很早以前就在asp.net 2.0中使用RegisterAsyncTask。当它与新的异步等待一起使用时,它感觉有些困难。代码执行的顺序是一个意想不到的。里克的文章中提到:“与RegisterInyncTask挂钩的方法将在PreRender之后立即运行”。所以我上面写的示例意味着DoSthAsync()实际上并不在Page_Load上运行? – Donald

1

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

await DoSthAsync();将有一个稍微高于一秒的执行时间。这是由于await关键字基本上意味着:等到异步操作成功完成,然后才执行下面的代码。这可以保证至少在这种情况下代码以同步样式运行,但长时间运行的操作的执行被调度为ThreadPool线程。这实际上是你想要的,但仍然存在在void返回的方法中使用异步/等待的缺点,这种方法不是非法的,但我不想这么做。你可以阅读它的缺点here

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

基本上,你有两个选择留下来获得你想要的结果:

  1. 用你的第一种方法,并与缺点生活。
  2. 重构您的代码,以便您可以通过使用包含EventHandlers的PageAsyncTask的另一个构造函数来使用第二种方法。您可以使用这些EventHandler来执行异步任务完成后应该运行的代码。你可以找到这种方法的一个很好的例子here

您将如何处理这些信息取决于您。请注意,我强烈建议您使用选项2。