當咱們用到C#類許多耗時的函數XXX時,總會存在同名的相似BeginXXX,EndXXX這樣的函數。編程
例如Stream抽象類的Read函數就有異步
public abstract int Read(byte[] buffer, int offset, int count); public virtual IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state); public virtual IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state);
這也就是所謂的APM異步編程模型,基於委託實現,其實就是啓動了一個後臺線程(主線程結束,則該線程結束),其中IAsyncResult就是異步狀態接口,用來檢測異步是否完成。async
每到大熱天的中午就不想動,出門就是一身汗,因此通常午飯時間我都選擇定外賣,正好等外賣這段時間還能夠完善一下上午的工做內容。這就至關於委託一名外賣小哥異步幫我送一份快餐過來,這段時間我繼續幹個人事情。異步編程
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace BeginInvoke { class Program { //聲明一個送外賣的委託類型 private delegate int DeliveryDelegate(string foodname);
static void Main(string[] args) { Console.WriteLine("天氣太熱,帶電話叫外賣小哥送一份番茄炒蛋"); //聲明一個外賣小哥,委託他去幫我拿午飯。 DeliveryDelegate DeliveryBoy = new DeliveryDelegate(GetFood); //開始CALL電話(異步調用,因爲還沒用到回調函數,後兩個參數填空) IAsyncResult ar = DeliveryBoy.BeginInvoke("番茄炒蛋", null, null); //繼續幹本身的事…… Console.WriteLine("完善上午的工做~大概5分鐘完成"); Thread.Sleep(1000); Console.WriteLine("完善20%"); Thread.Sleep(1000); Console.WriteLine("完善40%"); Thread.Sleep(1000); Console.WriteLine("完善60%"); Thread.Sleep(1000); Console.WriteLine("完善80%"); Thread.Sleep(1000); Console.WriteLine("完善100%"); Console.WriteLine("完善工做完成");//可是外賣還沒到 Console.WriteLine("等外賣……好餓,估計還要5分鐘纔到"); //此時調用EndInvoke會阻塞住線程直到異步調用完成,這時至關於我就主動蹲在門口等外賣小哥送上門,若是小哥先到,只能在門口等我辦完事~。 int money = DeliveryBoy.EndInvoke(ar); Console.WriteLine("給快遞小哥" + money + "元,開吃"); } /// <summary> /// 獲取食物 /// </summary> /// <param name="foodname">食物名</param> /// <returns>價格</returns> private static int GetFood(string foodname) { Console.WriteLine("外賣小哥頂着烈日送餐ing,預計10分鐘後到"); Thread.Sleep(10000); Console.WriteLine("外賣到達~" + foodname); //無論什麼菜一概10元錢! return 10; } } }
運行結果:函數
天氣太熱,帶電話叫外賣小哥送一份番茄炒蛋
完善上午的工做~大概5分鐘完成
外賣小哥頂着烈日送餐ing,預計10分鐘後到
完善20%
完善40%
完善60%
完善80%
完善100%
完善工做完成
等外賣……好餓,估計還要5分鐘纔到
外賣到達~番茄炒蛋
給快遞小哥10元,開吃spa
注:若是使用ar.AsyncWaitHandle.WaitOne();能夠設置指定等待時間間隔線程
if (ar.AsyncWaitHandle.WaitOne())//也會阻塞住線程直到異步調用完成,EndInvoke以後會自動收到Set信號。 { int money = DeliveryBoy.EndInvoke(ar); Console.WriteLine("給快遞小哥" + money + "元,開吃"); //若是調用ar.AsyncWaitHandle.WaitOne();,記得EndInvoke後要主動Close喲! ar.AsyncWaitHandle.Close(); }
以前的場景,若是我沒有作完工做,那麼外賣小哥只能在門口一直等我作完事情(沒辦法通知我外賣到了,只有我主動去檢查),這個時候回調函數就派上用處了,我就不再用擔憂外賣何時到,由於我又委託一我的專門幫我在門口盯着外賣小哥!code
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading; using System.Threading.Tasks; namespace BeginInvoke { class Program { //聲明一個送外賣的委託類型 private delegate int DeliveryDelegate(string foodname); static void Main(string[] args) { Console.WriteLine(DateTime.Now.ToString()); Console.WriteLine("天氣太熱,帶電話叫外賣小哥送一份番茄炒蛋"); //聲明一個外賣小哥,委託他去幫我拿午飯。 DeliveryDelegate DeliveryBoy = new DeliveryDelegate(GetFood); //開始CALL電話(異步調用,AsyncCallback其實也是一個delegate類型,實例化delegate委託一我的專門幫我在門口盯着外賣小哥) IAsyncResult ar = DeliveryBoy.BeginInvoke("番茄炒蛋", new AsyncCallback(GetFoodCallback), "番茄炒蛋"); //繼續幹本身的事…… Console.WriteLine("完善上午的工做~大概5分鐘完成"); Thread.Sleep(1000); Console.WriteLine("完善20%"); Thread.Sleep(1000); Console.WriteLine("完善40%"); Thread.Sleep(1000); Console.WriteLine("完善60%"); Thread.Sleep(1000); Console.WriteLine("完善80%"); Thread.Sleep(1000); Console.WriteLine("完善100%"); Console.WriteLine("完善工做完成");//可是外賣還沒到 Console.WriteLine("外賣估計還要5分鐘纔到,時間不等人,擼一盤"); //中途外賣到了,回調函數幫我付錢拿外賣,我繼續擼。 Console.WriteLine("LOL……一局10分鐘"); for (int i = 0; i < 10; i++) { Thread.Sleep(1000); Console.WriteLine("過去了1分鐘"); } Console.WriteLine("LOL拿到了首勝!,吃飯"); if (ar.IsCompleted) { Console.WriteLine("好吃~"); } } /// <summary> /// 獲取食物 /// </summary> /// <param name="foodname">食物名</param> /// <returns>價格</returns> private static int GetFood(string foodname) { Console.WriteLine("外賣小哥頂着烈日送餐ing,預計10分鐘後到"); Thread.Sleep(10000); Console.WriteLine("外賣到達~" + foodname); //無論什麼菜一概10元錢! return 10; } /// <summary> /// 異步完成,回調(完成時執行) /// 回調在 ThreadPool 線程上執行。 ThreadPool 線程是後臺線程,這些線程不會在主線程結束後保持應用程序的運行,所以示例的主線程必須休眠足夠長的時間以便回調完成。 /// </summary> /// <param name="ar">異步狀態</param> private static void GetFoodCallback(IAsyncResult ar) { AsyncResult result = (AsyncResult)ar; DeliveryDelegate dd = result.AsyncDelegate as DeliveryDelegate; int money = dd.EndInvoke(ar); string foodname = ar.AsyncState as string; Console.WriteLine("拿外賣!" + foodname + ",一共" + money + "元"); Console.WriteLine("付錢"); } } }
運行結果:blog
天氣太熱,帶電話叫外賣小哥送一份番茄炒蛋
完善上午的工做~大概5分鐘完成
外賣小哥頂着烈日送餐ing,預計10分鐘後到
完善20%
完善40%
完善60%
完善80%
完善100%
完善工做完成
外賣估計還要5分鐘纔到,時間不等人,擼一盤
LOL……一局10分鐘
過去了1分鐘
過去了1分鐘
過去了1分鐘
過去了1分鐘
過去了1分鐘
外賣到達~番茄炒蛋
拿外賣!番茄炒蛋,一共10元
付錢
過去了1分鐘
過去了1分鐘
過去了1分鐘
過去了1分鐘
過去了1分鐘
LOL拿到了首勝!,吃飯
好吃~接口
參考:
https://msdn.microsoft.com/zh-cn/library/ms228963(v=vs.110).aspx
https://msdn.microsoft.com/zh-cn/library/system.iasyncresult(v=vs.110).aspx
https://msdn.microsoft.com/zh-cn/library/2e08f6yc(v=vs.110).aspx