[C#.NET][Thread] 非同步作業 IAsyncResult / AsyncCallback
由上述連結可以得知:
非同步方法是.NET所提供的多執行緒操作,有支援非同步方法的會有一個叫BeginXXX方法和EndXXX方法。
1.BeginXXX 方法,會開始進行非同步作業,並回傳 IAsyncResult介面的物件,而 IAsyncResult 物件會儲存非同步作業的相關資訊。
IAsyncResult介面的屬性如下表:
2.EndXXX 方法,結束非同步方法的呼叫並取回結果
什麼時候會用到非同步方法?
當程式會需要大量運算、SQL資料庫連線、IO存取(資料複製)等等,為了不讓UI看起來像卡死,所以需要非同步方法。
在下面的例子裡我使用了超大迴圈進行大量運算。
使用IAsyncResult 非同步方式呼叫方法有幾個步驟:
1.建立委派簽章,簽章的參數需要與呼叫方法相同。
2.實體化委派。
3.使用BeginInvoke方法,建立非同步方法。
Note:等候非同步方法時,可以利用AsyncWaitHandle來鎖定主執行緒,使用 AsyncWaitHandle 封鎖應用程式執行。
4.詢問非同步方法是否完成。輪詢非同步作業的狀態
5.使用EndInvoke方法,結束呼叫並取得結果。
程式碼如下:
PS.在這個範例裡我在詢問狀態時,用了Application.DoEvents方法,這會讓這個迴圈工作時把執行權限暫時交回UI,讓畫面不會變成卡死的情況,但是他會讓CPU飆高,非常不建議你在你的類別裡使用Application.DoEvents方法;到目前為止它還算是同步方法,這樣的方式在專案多擺幾個想必CPU會飆高UI也會卡住,這時我們必須還需要借住AsyncCallback委派來進行非同步呼叫。
使用AsyncCallback非同步方式呼叫方法有幾個步驟:
1.建立委派簽章,簽章的參數需要與呼叫方法相同。
2.實體化委派。
3.建立Callback方法。
4.呼叫BeginInvoke方法時帶入AsyncCallback參數。
上述的程式需要不斷的詢問方法完成了沒,這樣不是個好方法,這時我們需要利用 AsyncCallback 委派,讓程式自動回報,
msdn上的簽章結構如下:
所以必須建立了一個具有IAsyncResult參數的Callback方法,利用它來執行EndInvoke。
完整範例如下:
當工作完成後自動會執行EndCallback方法,這樣一來我們就不需要使用IsComplete來判斷工作是否完成。
使用事件回報結果:
再來,我們可以利用事件在EndCallback觸發事件,我再加入一個委派AsyncEventArgs以及AsyncEventHandler
然後在EndCallback觸發AsyncEventHandler,這樣一來UI程序便能接收到回報事件狀態了。
完整程式碼如下
執行到這裡會發現,Form1_AsyncEventHandler無法回報結果至UI控制項,因為發生跨執行緒的例外,這時可以利用Control.Invoke , Control.BeginInvoke來解決
跨執行緒更新UI:
所以我再加入以下程式碼用來更新UI
所以在Form1_AsyncEventHandler裡面,就可以利用Control.BeginInvoke方法來呼叫。
參考資料: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