C# 創建線程的多種方式之異步調用基礎知識


創建線程一種簡單的方式是委托的異步調用,Delegate類提供了BeginInvoke方法,該方法可以傳遞委托類型定義的參數(所以BeginInvoke參數數量是可變的),另外還有2個固定的參數 回調函數委托AsynsCallBack和類型Object(如果不使用可直接賦值為null)。

BeginInvoke() 的返回值為IAsynResult,通過它的IsComplete屬性可以判斷異步調用是否完成。

        static void Main(string[] args)
        {
            Func<int, int> act1 = new Func<int, int>(Calculate);
            Console.WriteLine("Main Start....");
            IAsyncResult ar = act1.BeginInvoke(20,null, null);
            while (!ar.IsCompleted)
            {
                Console.WriteLine("Main is waiting");
                Thread.Sleep(500);
            }
            int result = act1.EndInvoke(ar);
            Console.WriteLine("Result is " + result);
            Console.ReadLine();
        }

        private static int Calculate(int total)
        {
            int sum = 0;
            for (int i = 0; i < total;i++ )
            {
                sum += i;
                Thread.Sleep(100);
            }
            return sum;
        }

運行返回結果:

Main Start....
Main is waiting
Main is waiting
Main is waiting
Main is waiting
Main is waiting
Result is 190

事實上,EndInvoke也是會等到異步調用結束,返回結果的。此外,IAsynResult的AsyncWaitHandle屬性是WaitHandle類型,利用WaitOne()能夠達到上述同樣的效果,我覺得有一個好處就是可以利用WaitAll()等待多個異步調用同時完成:

        static void Main(string[] args)
        {
            Func<int, int> act1 = new Func<int, int>(Calculate);
            Func<int, int> act2 = new Func<int, int>(Calculate);
            Console.WriteLine("Main Start....");
            IAsyncResult ar1 = act1.BeginInvoke(20,null, null);
            IAsyncResult ar2 = act2.BeginInvoke(30, null, null);
            if(WaitHandle.WaitAll(new WaitHandle[]{ar1.AsyncWaitHandle,ar2.AsyncWaitHandle},5000))
            {
                Console.WriteLine("Waiting is over");
                
            }
            int result1 = act1.EndInvoke(ar1);
            int result2 = act2.EndInvoke(ar2);
            Console.WriteLine("Result1 is {0},Result2 is {1}", result1, result2);
            Console.ReadLine();
        }

        private static int Calculate(int total)
        {
            int sum = 0;
            for (int i = 0; i < total;i++ )
            {
                sum += i;
                Thread.Sleep(100);
            }
            return sum;
        }

我聲明了act1和act2兩個委托對象,並同時進行異步調用,WaitHandle.WaitAll(new WaitHandle[]{ar1.AsyncWaitHandle,ar2.AsyncWaitHandle},5000) 等待同時完成,最后返回結果:

Main Start....
Waiting is over
Result1 is 190,Result2 is 435

 除了以上2種方式返回運行結果,還可以使用AsynsCallBack回調,BeginInvoke()的最后一個參數可以用ar.Asynstate訪問,以便在回調函數中使用,例如傳遞委托實例獲取運行結果:

        static void Main(string[] args)
        {
            Func<int, int> act1 = new Func<int, int>(Calculate);
            Console.WriteLine("Main Start....");
            IAsyncResult ar1 = act1.BeginInvoke(20, new AsyncCallback(CalculateComplete), act1);
            while(!ar1.IsCompleted){
                Console.WriteLine("Main is waiting");
                Thread.Sleep(500);
            }
            Console.ReadLine();
        }

        private static int Calculate(int total)
        {
            int sum = 0;
            for (int i = 0; i < total;i++ )
            {
                sum += i;
                Thread.Sleep(100);
            }
            return sum;
        }

        private static void CalculateComplete(IAsyncResult ar)
        {
            Console.WriteLine("Counting is over...........");
            Func<int, int> act = ar.AsyncState as Func<int, int>;
            Console.WriteLine("Result is "+act.EndInvoke(ar));
        }

運行結果:

Main Start....
Main is waiting
Main is waiting
Main is waiting
Main is waiting
Main is waiting
Counting is over...........
Result is 190

回調函數是在委托線程中完成的,還可以使用Lamda表達式,更加簡便,傳入最后一個參數,因為Lamda表達式可以訪問域外變量:

        static void Main(string[] args)
        {
            Func<int, int> act1 = new Func<int, int>(Calculate);
            Console.WriteLine("Main Start....");
            IAsyncResult ar1 = act1.BeginInvoke(20, ar => { Console.WriteLine("Result is " + act1.EndInvoke(ar)); }, null);
            while(!ar1.IsCompleted){
                Console.WriteLine("Main is waiting");
                Thread.Sleep(500);
            }
            Console.ReadLine();
        }

 


免責聲明!

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



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