Remoting之异步操作模式 - 中国WEB开发者网络 (http://www.webasp.net) -- 技术教程 (http://www.webasp.net/article/) --- Remoting之异步操作模式 (http://www.webasp.net/article/28/27640.htm) |
| -- 作者:未知 -- 发布日期: 2006-05-16 |
| 如果你还不知道什么是异步也不要紧,我们还是来看实例,通过实例来理解才是最深刻的。 在Remoting中,我们可以使用以下几种异步的方式: 1、普通异步 2、回调异步 3、单向异步 一个一个来说,首先我们这么修改我们的远程对象: public int ALongTimeMethod(int a,int b,int time) { Console.WriteLine("异步方法开始"); System.Threading.Thread.Sleep(time); Console.WriteLine("异步方法结束"); return a+b; } 这个方法传入2个参数,返回2个参数和表示方法执行成功,方法需要time毫秒的执行时间,这是一个长时间的方法。 如果方法我们通过异步远程调用,这里需要注意到这个方法输出的行是在服务器端输出的而不是客户端。因此,为了测试简单,我们还是在采用本地对象,在实现异步前我们先来看看同步的调用方法,为什么说这是一种阻塞?因为我们调用了方法主线程就在等待了,看看测试: DateTime dt=DateTime.Now; RemoteObject.MyObject app=new RemoteObject.MyObject(); Console.WriteLine(app.ALongTimeMethod(1,2,1000)); Method(); Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒"); Console.ReadLine(); 假设method方法是主线程的方法,需要3秒的时间: private static void Method() { Console.WriteLine("主线程方法开始"); System.Threading.Thread.Sleep(3000); Console.WriteLine("主线程方法结束"); } 好了,现在开始运行程序: ![]() 用了4秒,说明在我们的方法开始以后本地就一直在等待了,总共用去的时间=本地方法+远程方法,对于长时间方法调用这显然不科学!我们需要改进: 1、普通异步: 首先在main方法前面加上委托,签名和返回类型和异步方法一致。 private delegate int MyDelegate(int a,int b,int time); main方法里面这么写: DateTime dt=DateTime.Now; RemoteObject.MyObject app=new RemoteObject.MyObject(); MyDelegate md=new MyDelegate(app.ALongTimeMethod); IAsyncResult Iar=md.BeginInvoke(1,2,1000,null,null); Method(); if(!Iar.IsCompleted) { Iar.AsyncWaitHandle.WaitOne(); } else { Console.WriteLine("结果是"+md.EndInvoke(Iar)); } Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒"); Console.ReadLine(); 来看一下执行结果: ![]() 现在总共执行时间接近于主线程的执行时间了,等于是调用方法基本不占用时间。 分析一下代码:Iar.AsyncWaitHandle.WaitOne(); 是阻塞等待异步方法完成,在这里这段代码是不会被执行的,因为主方法完成的时候,异步方法早就IsCompleted了,如果我们修改一下代码:IAsyncResult Iar=md.BeginInvoke(1,2,5000,null,null); ![]() 可以看到,主线程方法结束后就在等待异步方法完成了,总共用去了接近于异步方法的时间:5秒。 在实际的运用中,主线程往往需要得到异步方法的结果,也就是接近于上述的情况,我们在主线程做了少量时间的工作以后最终要是要WaitOne去等待异步操作返回的结果,才能继续主线程操作。看第二个图可以发现,异步操作仅仅用了1秒,但是要等待3秒的主线程方法完成后再返回结果,这还是不科学啊。因此,我们要使用委托回调的异步技术。 2、回调异步: class MyClient { private delegate int MyDelegate(int a,int b,int time); private static MyDelegate md; [STAThread] static void Main(string[] args) { DateTime dt=DateTime.Now; //RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]); RemoteObject.MyObject app=new RemoteObject.MyObject(); md=new MyDelegate(app.ALongTimeMethod); AsyncCallback ac=new AsyncCallback(MyClient.CallBack); IAsyncResult Iar=md.BeginInvoke(1,2,1000,ac,null); Method(); Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒"); Console.ReadLine(); } public static void CallBack(IAsyncResult Iar) { if(Iar.IsCompleted) { Console.WriteLine("结果是"+md.EndInvoke(Iar)); } } private static void Method() { Console.WriteLine("主线程方法开始"); System.Threading.Thread.Sleep(3000); Console.WriteLine("主线程方法结束"); } } 可以看到我上面的注释行,去掉远程调用的注释,对下面的本地调用注释,编译后启动服务端,再启动客户端就是远程调用了。
using System; using System.Runtime.Remoting.Messaging; namespace RemoteObject { public class MyObject:MarshalByRefObject { [OneWay] public void ALongTimeMethodOneWay(int time) { Console.WriteLine("异步方法开始"); System.Threading.Thread.Sleep(time); Console.WriteLine("异步方法结束"); } } } [OneWay]属性是Remoting.Messaging的一部分,别忘记using,下面看看客户端代码: using System; namespace RemoteClient { class MyClient { [STAThread] static void Main(string[] args) { DateTime dt=DateTime.Now; RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]); //RemoteObject.MyObject app=new RemoteObject.MyObject(); app.ALongTimeMethodOneWay(1000); Method(); Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒"); Console.ReadLine(); } private static void Method() { Console.WriteLine("主线程方法开始"); System.Threading.Thread.Sleep(3000); Console.WriteLine("主线程方法结束"); } } } 这次我们仅仅只能在远程调试,我们先让异步方法去做,然后就放心的做主线程的事情,其他不管了。 |
| webasp.net |