[C#.NET][Thread] 非同步作業 IAsyncResult / AsyncCallback

[C#.NET][Thread] 非同步作業 IAsyncResult / AsyncCallback

非同步程式設計概觀

由上述連結可以得知:

非同步方法是.NET所提供的多執行緒操作,有支援非同步方法的會有一個叫BeginXXX方法和EndXXX方法。

1.BeginXXX 方法,會開始進行非同步作業,並回傳 IAsyncResult介面的物件,而 IAsyncResult 物件會儲存非同步作業的相關資訊。

IAsyncResult介面的屬性如下表:

image

 

2.EndXXX 方法,結束非同步方法的呼叫並取回結果

 

什麼時候會用到非同步方法?

當程式會需要大量運算、SQL資料庫連線、IO存取(資料複製)等等,為了不讓UI看起來像卡死,所以需要非同步方法。

在下面的例子裡我使用了超大迴圈進行大量運算。

 

使用IAsyncResult 非同步方式呼叫方法有幾個步驟:

1.建立委派簽章,簽章的參數需要與呼叫方法相同。

2.實體化委派。

3.使用BeginInvoke方法,建立非同步方法。

  Note:等候非同步方法時,可以利用AsyncWaitHandle來鎖定主執行緒,使用 AsyncWaitHandle 封鎖應用程式執行

4.詢問非同步方法是否完成。輪詢非同步作業的狀態

5.使用EndInvoke方法,結束呼叫並取得結果。

 

程式碼如下:

 

 

image

 

 

PS.在這個範例裡我在詢問狀態時,用了Application.DoEvents方法,這會讓這個迴圈工作時把執行權限暫時交回UI,讓畫面不會變成卡死的情況,但是他會讓CPU飆高,非常不建議你在你的類別裡使用Application.DoEvents方法;到目前為止它還算是同步方法,這樣的方式在專案多擺幾個想必CPU會飆高UI也會卡住,這時我們必須還需要借住AsyncCallback委派來進行非同步呼叫。

使用AsyncCallback非同步方式呼叫方法有幾個步驟:

1.建立委派簽章,簽章的參數需要與呼叫方法相同。

2.實體化委派。

3.建立Callback方法。

4.呼叫BeginInvoke方法時帶入AsyncCallback參數。

上述的程式需要不斷的詢問方法完成了沒,這樣不是個好方法,這時我們需要利用 AsyncCallback 委派,讓程式自動回報,

msdn上的簽章結構如下:

image

 

所以必須建立了一個具有IAsyncResult參數的Callback方法,利用它來執行EndInvoke。

image

 

完整範例如下:

當工作完成後自動會執行EndCallback方法,這樣一來我們就不需要使用IsComplete來判斷工作是否完成。

 

 

image

 

 

使用事件回報結果:

再來,我們可以利用事件在EndCallback觸發事件,我再加入一個委派AsyncEventArgs以及AsyncEventHandler

image

 

然後在EndCallback觸發AsyncEventHandler,這樣一來UI程序便能接收到回報事件狀態了。

image

 

完整程式碼如下

image

 

 

 

 

 

執行到這裡會發現,Form1_AsyncEventHandler無法回報結果至UI控制項,因為發生跨執行緒的例外,這時可以利用Control.Invoke , Control.BeginInvoke來解決

image

 

跨執行緒更新UI:

所以我再加入以下程式碼用來更新UI

image

 

所以在Form1_AsyncEventHandler裡面,就可以利用Control.BeginInvoke方法來呼叫。

image

 

參考資料:IsAsyncResult_CS.zip

http://blog.darkthread.net/blogs/darkthreadtw/archive/2008/03/26/better-winform-ui.aspx

http://www.dotblogs.com.tw/kirkchen/archive/2010/12/28/20435.aspx

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo