簡體   English   中英

ASP.NET異步任務執行序列

[英]ASP.NET async task execution sequence

我只是在asp.net上遇到並發編碼,發現在Page_Load方法中有兩種觸發異步方法的方法

  1. RegisterAsyncTask(new PageAsyncTask(DoSthAsync()));
  2. 等待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

在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();
.......

盡管我像上面的代碼片段一樣使用它,但是在RegisterAsyncTaskawait 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的缺點,這不是非法的,但我會避免這樣做。 您可以在此處閱讀其缺點的所有內容。

使用RegisterAsyncTaskPageAsyncTask的第二種方法的執行時間將小於1秒。 這是因為它只注冊要執行的任務,然后立即返回以處理下面的代碼。 由於您的代碼是在Page_Load事件中編寫的,因此長時間運行的操作將僅在PreRenderComplete事件完成后自動開始。 但是您可以使用Page.ExecuteRegisteredAsyncTasks();手動開始執行任務Page.ExecuteRegisteredAsyncTasks(); 但請注意:這也不會等待任務完成,而只會更早開始執行。

基本上,您還有兩個選擇來獲得所需的結果:

  1. 使用您的第一種方法並忍受不利之處。
  2. 重構代碼,以便可以通過使用包含EventHandlers的PageAsyncTask的另一個構造函數來使用第二種方法。 您可以使用這些EventHandlers執行應在異步任務完成后運行的代碼。 您可以在這里找到這種方法的一個很好的例子。

您將如何處理此信息。 請注意,我強烈建議您使用選項2。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM