異步多線程(一)委托異步多線程


進程

計算機概念,程序在服務器運行時占據全部計算機資源總和,虛擬的。包含CPU、內存、網絡、硬盤

MSDN:

當一個程序開始運行時,它就是一個進程,進程包括運行中的程序和程序所使用到的內存和系統資源。

而一個進程又是由多個線程所組成的。

 

 

線程

計算機概念,進程在響應操作時最小單位,也包含CPU、內存、網絡、硬盤

MSDN:              

線程是程序中的一個執行流,每個線程都有自己的專有寄存器(棧指針、程序計數器等),但代碼區是共享的,即不同的線程可以執行同樣的函數。

 

 

多線程

計算機概念,一個進程有多個線程同時運行。

MSDN:

    多線程是指程序中包含多個執行流,即在一個程序中可以同時運行多個不同的線程來執行不同的任務,也就是說允許單個程序創建多個並行執行的線程來完成各自的任務。

 

為什么可以多線程

      多個CPU的核可以並行工作,

        48線程,這里的線程指的是模擬核

CPU分片

1s的處理能力分成1000份,操作系統調度着去響應不同的任務

        從宏觀角度來說,就是多個任務在並發執行

        從微觀角度來說,一個物理cpu同一時刻只能為一個任務服務

 

並行:多核之間叫並行

並發CPU分片的並發

 

 多線程其實是資源換性能,1 資源不是無限的  2 資源調度損耗

 

多線程的好處: 

可以提高CPU的利用率。在多線程程序中,一個線程必須等待的時候,CPU可以 運行其它的線程而不是等待,這樣就大大提高了程序的效率。

 

多線程的不利之處

線程也是程序,所以線程需要占用內存,線程越多占用內存也越多; 多線程需要協調和管理,所以需要CPU時間跟蹤線程; 

線程之間對共享資源的訪問會相互影響,必須解決競用共享資源的問題;線程太多會導致控制太復雜,最終可能造成很多Bug

 

同步與異步

同步:

     發起調用,完成后才繼續下一行;非常符合開發思維,有序執行;

異步:

發起調用,不等待完成,直接進入下一行,啟動一個新線程來完成方法的計算

 

同步方法有序進行,異步多線程無序
  啟動無序:線程資源是向操作系統申請的,由操作系統的調度策略決定,所以啟動順序隨機。同一個任務同一個線程,執行時間也不確定,CPU分片
以上相加,結束也無序

同步方法慢,異步多線程方法快

  同步:只有一個線程計算 異步:因為多個線程並發計算

 

同步方法卡界面,異步多線程方法不卡界面

  同步方法:            主線程(UI線程)忙於計算,無暇他顧
  異步多線程方法: 異步多線程方法不卡界面:主線程閑置,計算任務交給子線程完成

 

同步代碼示例:

 

        /// <summary>
        /// 同步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {

            Console.WriteLine($"button1_Click*****Start{Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString()}");
            for (int i = 0; i < 5; i++)
            {
                string name = string.Format($"button1_Click{i}");
                this.DoSomethingLong(name);
            }

            Console.WriteLine($"button1_Click*****End{Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString()}");
        }

 

程序執行完成,我們可以清晰的看到,同步方法是有序的執行

 

 

委托異步多線程代碼示例:

        /// <summary>
        /// 異步多線程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click_1(object sender, EventArgs e)
        {
            Console.WriteLine($"****************button2_Click Start " +
                $"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
                $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            Action<string> action = this.DoSomethingLong;
         
            for (int i = 0; i < 5; i++)
            {
                string name = string.Format($"button2_Click_1{i}");
                action.BeginInvoke("button2_Click", null, null);//委托異步多線程調用

            }

            Console.WriteLine($"****************button2_Click End " +
                $"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
                $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

        }

程序運行之后,我們會發現運行的結果是無序的

 

委托異步多線程 回調

將后續動作通過回調參數傳遞進去,子線程完成計算后,去調用這個回調委托。

代碼示例:

 

        /// <summary>
        /// 異步多線程回調、等待
        /// Action
        /// Func
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            #region  回調
            {
                Action<string> action = this.DoSomethingLong;
                IAsyncResult asyncResult = null;//是對異步調用操作的描述
                AsyncCallback callback = mm =>
                {//這里是一個委托

                    Console.WriteLine($"{object.ReferenceEquals(mm, asyncResult)}");
                    Console.WriteLine($"button3_Click計算成功了。{mm.AsyncState}。{Thread.CurrentThread.ManagedThreadId.ToString("00")}");

                };

                //回調

                action.BeginInvoke("button3_Click", callback, "嘿嘿");//先執行action然后回調 callback委托
            }
            #endregion


        }

 

 

 

委托異步多線程等待的三種方式:

 

IsComplate等待

 

通過IsComplate等待,主線程在等待,邊等待邊提示

 

            #region IsComplate等待
            {
                Action<string> action = this.DoSomethingLong;
                IAsyncResult asyncResult = null;//是對異步調用操作的描述
                AsyncCallback callback = mm =>
                {
                    Console.WriteLine($"{object.ReferenceEquals(mm, asyncResult)}");
                    Console.WriteLine($"button3_Click計算成功了。{mm.AsyncState}。{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                };
                //回調
                asyncResult= action.BeginInvoke("button3_Click", callback, "嘿嘿");//先執行action然后回調 callback委托
                int i = 0;
                while (!asyncResult.IsCompleted)
                {
                    Thread.Sleep(200);
                    if (i < 2)
                    {
                        Console.WriteLine($"正在充電{++i * 10}%....");

                    } else{
                        Console.WriteLine($"充電完成完成99.999999%....");
                    }
                 
                }
                Console.WriteLine("充電已完成,盡情的使用手機吧!");

            }

            #endregion

 

程序執行完成的結果

注意:根據調用,首先執行DoSomethingLong 方法,因為DoSomethingLong方法里有密集操作,所以程序會邊等待邊執行while里的判斷語句以及方法體

此時DoSomethingLong里的密集操作已執行完畢,接着執行callback里的方法

 

 

WaitOne等待

 

WaitOne等待,即時等待  限時等待

 asyncResult.AsyncWaitHandle.WaitOne();//直接等待任務完成
asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任務完成
asyncResult.AsyncWaitHandle.WaitOne(1000);//最多等待1000ms,超時就不等了

 

 

EndInvoke等待

即時等待,而且可以獲取委托的返回值 一個異步操作只能End一次

 

            #region EndInvoke 
            Func<int> func = ()=>
            {
                Thread.Sleep(2000);
return DateTime.Now.Hour; }; int Result = func.Invoke(); IAsyncResult asyncResult = func.BeginInvoke(ar=> { //在方法里拿到結果 // int IResult = func.EndInvoke(ar); //對於每個異步操作,只能調用一次EndInvoke }, null); //在方法外得到結果 int EndResult = func.EndInvoke(asyncResult); #endregion

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM