1. 程式人生 > >11 非同步多執行緒(一)

11 非同步多執行緒(一)

任何的非同步多執行緒,都是和委託相關,沒有委託,啥也沒有。

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}");
 }, "小呀麼小西瓜");