2016-03-07 195 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。