我是2004年打仗并运用C#的,当时C#版本为1.1,所以我们就从就那个时候谈起。当时在大学里本身看誊写顺序,所写的顺序大都是同步顺序,最多启动个线程........其实在C#1.1的时期已有完全的异步编程解决方案,那就是APM(异步编程模子)。假如另有不相识“同步顺序、异步顺序”的请自行百度哦。
APM异步编程模子最具代表性的特点是:一个异步功用由以Begin开首、End开首的两个要领构成。Begin开首的要领示意启动异步功用的实行,End开首的要领示意守候异步功用实行完毕并返回实行效果。下面是一个模仿的完成体式格局(背面将编写规范的APM模子异步完成):
public class Worker { public int A { get; set; } public int B { get; set; } private int R { get; set; } ManualResetEvent et; public void BeginWork(Action action) { et = new ManualResetEvent(false); new Thread(() => { R = A + B; Thread.Sleep(1000); et.Set(); if(null != action) { action(); } }).Start(); } public int EndWork() { if(null == et) { t hrow new Exception("挪用EndWork前,须要先挪用BeginWork"); } else { et.WaitOne(); return R; } } }
static void Main(string[] args) { Worker w = new Worker(); w.BeginWork(()=> { Console.WriteLine("Thread Id:{0},Count:{1}", Thread.CurrentThread.ManagedThreadId, w.EndWork()); }); Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId); Console.ReadLine(); }
在上面的模仿APM模子中我们运用了 Thread、ManualResetEvent,假如你对多线程和ManualResetEvent不熟悉C#中运用异步编程不可避免的会涉及到多线程的学问,虽然微软在Framework中做了许多封装,但朋侪们应当控制其本质。
上面模仿的APM异步模子之所以简朴,是由于C#生长历程当中引入了许多优异的语法划定规矩。上例我们较多的运用了Lambda表达式,假如你不熟悉 匿名托付与lambda表达式可看我之前的Bolg《匿名托付与Lambda表达式》。上面做了云云多的广告,下面我们来看一下规范的APM模子怎样完成异步编程。
IAsyncResult接口
IAsyncResult接口定义了异步功用的状况,该接口细致属性及寄义以下:
// 示意异步操纵的状况。 [ComVisible(true)] public interface IAsyncResult { // // 择要: // 猎取一个值,该值指导异步操纵是不是已完成。 // // 返回效果: // 假如操纵已完成,则为 true;否则为 false。 bool IsCompleted { get; } // // 择要: // 猎取用于守候异步操纵完成的 System.Threading.WaitHandle。 // // 返回效果: // 用于守候异步操纵完成的 System.Threading.WaitHandle。 WaitHandle AsyncWaitHandle { get; } // // 择要: // 猎取一个用户定义的对象,该对象限制或包括有关异步操纵的信息。 // // 返回效果: // 一个用户定义的对象,限制或包括有关异步操纵的信息。 object AsyncState { get; } // // 择要: // 猎取一个值,该值指导异步操纵是不是同步完成。 // // 返回效果: // 假如异步操纵同步完成,则为 true;否则为 false。 bool CompletedSynchronously { get; } }
注重:模子示例1中的 ManualResetEvent 继续自 WaitHandle
APM传说完成体式格局
在相识了IAsyncResult接口后,我们来经由历程完成 IAsyncResult 接口的体式格局完成对模仿示例的改写事情,代码以下:
public class NewWorker { public class WorkerAsyncResult : IAsyncResult { AsyncCallback callback; public WorkerAsyncResult(int a,int b, AsyncCallback callback, object asyncState) { A = a; B = b; state = asyncState; this.callback = callback; new Thread(Count).Start(this); } public int A { get; set; } public int B { get; set; } public int R { get; private set; } private object state; public object AsyncState { get { return state; } } private ManualResetEvent waitHandle; public WaitHandle AsyncWaitHandle { get { if (null == waitHandle) { waitHandle = new ManualResetEvent(false); } return waitHandle; } } private bool completedSynchronously; public bool CompletedSynchronously { get { return completedSynchronously; } } private bool isCompleted; public bool IsCompleted { get { return isCompleted; } } private static void Count(object state) { var result = state as WorkerAsyncResult; result.R = result.A + result.B; Thread.Sleep(1000); result.completedSynchronously = false; result.isCompleted = true; ((ManualResetEvent)result.AsyncWaitHandle).Set(); if (result.callback != null) { result.callback(result); } } } public int Num1 { get; set; } public int Num2 { get; set; } public IAsyncResult BeginWork(AsyncCallback userCallback, object asyncState) { IAsyncResult result = new WorkerAsyncResult(Num1,Num2,userCallback, asyncState); return result; } public int EndWork(IAsyncResult result) { WorkerAsyncResult r = result as WorkerAsyncResult; r.AsyncWaitHandle.WaitOne(); return r.R; } }
示例代码剖析:
上面代码中NewWorker的内部类 WorkerAsyncResult 是症结点,它完成了 IAsyncResult 接口并由它来担任开启新线程完成盘算事情。
在WorkerAsyncResult中增添了 A、B两个私有属性来存储用于盘算的数值,一个对外可读不可写的属性R,用于存储WorkerAsyncResult内部运算的效果。AsyncWaitHandle属性由 ManualResetEvent 来充任,并在初次接见时建立ManualResetEvent(但不开释)。其他接口属性一般完成,没有什么可说。
WorkerAsyncResult 中新增 static Count 要领,参数 state 为挪用Count要领的当前WorkerAsyncResult对象。Count 要领在 WorkerAsyncResult 对象的新启线程中运转,因而Thread.Sleep(1000)将壅塞新线程1秒中。然后设置当前WorkerAsyncResult对象是不是同步完成为false,异步完成状况为true,开释ManualResetEvent关照以便守候线程猎取关照进入实行状况,推断是不是有异步实行完毕回调托付,存在则回调之。
NewWorker 异常简朴,Num1、Num2两个属性为要盘算的数值。BeginWork 建立WorkerAsyncResult对象、并将要盘算的两个数值Num1、Num2、userCallback回调托付、object 范例的 asyncState 传入要建立的WorkerAsyncResult对象。经由此步操纵,WorkerAsyncResult对象猎取了运算所需的一切数据、运算完成后的回调,并立时启动新线程举行运算(实行WorkerAsyncResult.Count要领)。
由于WorkerAsyncResult.Count实行在新线程中,在该线程外部没法正确获知新线程的状况。为了满足外部线程与新线程同步的需求,在NewWorker中增添EndWork要领,参数范例为IAsyncResult。要挪用EndWork要领应传入BeginWork 猎取的WorkerAsyncResult对象,EndWork要领猎取WorkerAsyncResult对象后,挪用WorkerAsyncResult.AsyncWaitHandle.WaitOne()要领,守候猎取ManualResetEvent关照,在猎取到关照时运算线程已运算完毕(线程并未完毕),下一步猎取运算效果R并返回。
接下来是NewWorker挪用顺序,以下:
static void Main(string[] args) { NewWorker w2 = new NewWorker(); w2.Num1 = 10; w2.Num2 = 12; IAsyncResult r = null; r = w2.BeginWork((obj) => { Console.WriteLine("Thread Id:{0},Count:{1}",Thread.CurrentThread.ManagedThreadId, w2.EndWork(r)); }, null); Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId); Console.ReadLine(); }
下图我简朴画的顺序挪用历程,有助于各位朋侪明白:
规范的APM模子异步编程,对应开辟人员来讲过于庞杂。因而经由历程完成 IAsyncResult 接口举行异步编程,就是传说中的中看不中用(罪行罪行.....)。
Delegate异步编程(APM 规范完成)
C#中托付天生支撑异步挪用(APM模子),任何托付对象后"."就会发明BeginInvoke、EndInvoke、Invoke三个要领。BeginInvoke为异步体式格局挪用托付、EndInvoke守候托付的异步挪用完毕、Invoke同步体式格局挪用托付。因而上面的规范APM实例,可借助 delegate 举行以下简化。
上面NewWorker运用托付体式格局改写以下:
public class NewWorker2 { Func<int, int, int> action; public NewWorker2() { action = new Func<int, int, int>(Work); } public IAsyncResult BeginWork(AsyncCallback callback, object state) { dynamic obj = state; return action.BeginInvoke(obj.A, obj.B, callback, this); } public int EndWork(IAsyncResult asyncResult) { try { return action.EndInvoke(asyncResult); } catch (Exception ex) { throw ex; } } private int Work(int a, int b) { Thread.Sleep(1000); return a + b; } }
挪用顺序:
static void Main(string[] args) { NewWorker2 w2 = new NewWorker2(); IAsyncResult r = null; r = w2.BeginWork((obj) => { Console.WriteLine("Thread Id:{0},Count:{1}", Thread.CurrentThread.ManagedThreadId, w2.EndWork(r)); }, new { A = 10, B = 11 }); Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId); Console.ReadLine(); }
上面的运用托付举行APM异步编程,比完成 IAsyncResult 接口的体式格局精简太多、更容易明白运用。因而这里发起朋侪们 delegate 异步挪用模子应当控制起来,而经由历程完成 IAsyncResult 接口的传说体式格局看你的喜好吧。
以上就是C#异步之APM形式异步顺序开辟的示例分享的细致内容,更多请关注ki4网别的相干文章!