11 非同步多執行緒(一)
阿新 • • 發佈:2018-12-09
任何的非同步多執行緒,都是和委託相關,沒有委託,啥也沒有。
BeginInvoke在 C#裡面,就是啟動一個執行緒完成任務。
用設定斷點的方法來除錯的非同步多執行緒,是行不通的,只有多寫一些日誌或者輸出文字資訊到控制檯程式上。
如果要想看到控制檯程式一樣的介面輸出結果,則在專案上點右鍵--屬性,
同步方法和非同步多執行緒區別:
1.同步方法卡介面,因為UI執行緒忙於計算;非同步多執行緒不卡介面,主執行緒閒置,計算任務交給子執行緒在做。
2.同步方法慢,只有一個執行緒計算;非同步多執行緒方法快,多個執行緒併發計算。多執行緒的資源消耗更多,但執行緒並不是越多越好(資源有限/管理執行緒也消耗資源)。具體開多個執行緒也不是定死的,要通過實際情況。
3.非同步多執行緒是無序的,啟動無序,執行時間不確定,結束無序,所以我們不要試圖通過啟動順序或者時間等待來控制流程。
看一下這個圖:
原因如下:
當多執行緒執行時,多個請求跑進來問執行緒池要執行緒,執行緒池裡面的執行緒又是通過CLR向操縱系統申請的,哪個請求先拿到執行緒,要看作業系統分配,執行緒池掌控不了,所以是無序的。
怎麼控制順序呢?有回撥、等待、狀態。
1.回撥
最推薦的是回撥,不卡介面、
Action<string> act = this.DoSomethingLong; IAsyncResult iAsyncResult = null; //回撥方法 AsyncCallback callback = ar => { Console.WriteLine(object.ReferenceEquals(ar, iAsyncResult)); Console.WriteLine(ar.AsyncState); Console.WriteLine($"這裡是BeginInvoke呼叫完成之後才執行的。。。{Thread.CurrentThread.ManagedThreadId.ToString("00")}"); };
iAsyncResult = act.BeginInvoke("btnAsync_Click", callback, "asyncState");
2.等待
1)IsComplated
Action<string> act = this.DoSomethingLong; IAsyncResult iAsyncResult = act.BeginInvoke("btnAsync_Click", null, null); int i = 1; //1 卡介面,主執行緒在等待 2 邊等待邊做事兒 3有誤差 while (!iAsyncResult.IsCompleted) { if (i < 10) { Console.WriteLine($"檔案上傳{i++ * 10}%。。。請等待"); } else { Console.WriteLine("已完成99%。。。馬上結束"); } Thread.Sleep(200); } Console.WriteLine("檔案上傳成功!!!");
2)WaitOne
iAsyncResult.AsyncWaitHandle.WaitOne();//一直等待任務完成,第一時間進入下一行
iAsyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任務完成,第一時間進入下一行
iAsyncResult.AsyncWaitHandle.WaitOne(1000);//最多等待1000ms,否則就進入下一行,可以做一些超時控制
WaitOne用的比較少,它還不如 IsComplated 好用,IsComplated雖然卡介面,但主執行緒還可以做其他事情,比如輸出提示語句。WaitOne卡在那裡什麼都不能做。
3)EndInvoke,可以獲取非同步的呼叫結果
Func<int, string> func = i => i.ToString();
IAsyncResult iAsyncResult = func.BeginInvoke(DateTime.Now.Year, ar =>
{
string resultIn = func.EndInvoke(ar);//對於每個非同步操作,只能呼叫一次 EndInvoke。
Console.WriteLine($"This is {ar.AsyncState} 的非同步呼叫結果 {resultIn}");
}, "小呀麼小西瓜");