標籤:
這篇文章僅當總結之用,參考了很多前輩們的文章,加上了點點自己的理解
C#的同步和非同步線程是依靠委託來完成,主要需要用到委託的Invoke方法,BeginInvoke和EndInvoke方法
所謂同步線就是阻塞當前線程來完成調用的方法,然後才繼續調用當前線程的後面的操作,實際上都是在同一個線程中執行,效率不高。需要用到Invoke方法
非同步線程不阻塞當前線程,而是把需要調用的方法加入線程池中,來同步執行,即同一時間兩個及其以上的線程共同都在執行,效率很高。需要用到BeginInvoke和EndInvoke方法
具體請看下面的源碼和注釋(PS:絕大多數總結都在注釋當中了)
using System;using System.Collections.Generic;using System.ComponentModel;using System.Linq;using System.Runtime.Remoting.Messaging;using System.Text;using System.Threading;using System.Threading.Tasks;namespace AsyncRe{ class Program { static void Main(string[] args) { ImportantFun it=new ImportantFun(); //依次示範同步調用 不完全非同步呼叫 全非同步呼叫 it.Sync(); it.TerribleAsync(); it.Async(); } } //定義一個委託類型 public delegate int AddHandler(int x, int y); /// <summary> /// 示範同步調用和非同步呼叫 /// </summary> class ImportantFun { //被調用的方法 private int Add(int x, int y) { //用於顯示當前方法所在的線程 Console.WriteLine("Add is running on thread"+Thread.CurrentThread.ManagedThreadId); //線程停滯6s Thread.Sleep(6000); return x + y; } /// <summary> /// 同步調用Add /// </summary> public void Sync() { Console.WriteLine("*********示範同步調用********"); //列印當前方法所在的線程 Console.WriteLine("Sync is running on thread"+Thread.CurrentThread.ManagedThreadId); AddHandler handler=new AddHandler(Add); //Invoke用於同步調用 int Result = handler.Invoke(1, 2); Console.WriteLine("Add is Compete"); Console.WriteLine("Result="+Result); Console.ReadKey(); } /// <summary> /// 不完整的非同步呼叫,具體見下面注釋 /// </summary> public void TerribleAsync() { Console.WriteLine("***********示範不完整非同步呼叫**********"); Console.WriteLine("TerribaleAsync is running on thread"+Thread.CurrentThread.ManagedThreadId); AddHandler handler=new AddHandler(Add); //非同步呼叫一般用委託的BegInvoke和EndInvoke搭配在一起完成 //BeginInvoke表示非同步呼叫開始 返回一個表示調用狀態的介面(IAsyncResult) IAsyncResult iar = handler.BeginInvoke(1, 2, null, null); //上面本該有4個參數,暫且把3,4號參數定為null Console.WriteLine("TerribaleAsync is running on thread" + Thread.CurrentThread.ManagedThreadId); Console.WriteLine(iar.ToString()); //EndInvoke表示非同步呼叫時的方法,參數是IAsyncResult類型 int result = handler.EndInvoke(iar); Console.WriteLine(result); Console.WriteLine("此種非同步呼叫的方法有缺陷,在EndInvoke後面的方法同樣被阻隔,只能保證Begin和End中間是非同步"); Console.ReadKey(); //此種非同步呼叫的方法有缺陷,在EndInvoke後面的方法同樣被阻隔,只能保證Begin和End中間是非同步 //解決辦法是利用BeginInvoke中的3號和4號參數,將EndInvoke列在回呼函數當中 //實際上就是為了避免EndInvoke出現在其他地方,利用BegingInvoke方法一次性調用它。見下面的方法 } /// <summary> /// 完整非同步呼叫 原理就是在beginInvoke中調用End /// </summary> public void Async() { Console.WriteLine("***********示範非同步呼叫**********"); Console.WriteLine("Async is running on thread"+Thread.CurrentThread.ManagedThreadId); AddHandler handler=new AddHandler(Add); //new AsyncCallback(Callback)回呼函數,非同步呼叫結束時,runtime會自動調用該函數 //"Async parameter is me"作為回調參數 可以通過Async.AsyncState擷取 handler.BeginInvoke(1, 2, new AsyncCallback(CallBack), "Async parameter is me"); // 上面 一個委託,回呼函數 回調參數 Console.WriteLine("Async is running on thread "+Thread.CurrentThread.ManagedThreadId); //利用這步的輸出結果可以驗證是否是全非同步。 Console.ReadKey(); } /// <summary> /// 回呼函數 /// </summary> /// <param name="iar"></param> private void CallBack(IAsyncResult iar) { Console.WriteLine("CallBack is running on thread"+Thread.CurrentThread.ManagedThreadId); //前者是非同步作業的結果 後者代表過程中的所有 AsyncResult Ar = (AsyncResult) iar; //擷取原委派物件 注意強制轉換 AddHandler handler = (AddHandler) Ar.AsyncDelegate; //結束委託調用 得到結果 int result = handler.EndInvoke(Ar); //輸出上面的Begin中的第4個參數 Console.WriteLine("The Async calling parameter is "+Ar.AsyncState); //輸出結果 Console.WriteLine("Result ="+result); } } }
從圖片可以看出 同步調用都是在一個線程當中
非同步呼叫時再其他線程當中進行,特別注意理解回呼函數
一切的操作主要需要用到Invoke方法,BeginInvoke,EndInvoke,深刻理解三個函數的意義和參數就能夠理解同步和非同步呼叫
希望對大家有用。
C#同步和非同步呼叫