一步一步学Remoting之五:异步操作<转>

简介:
 一步一步学Remoting之五:异步操作

如果你还不知道什么是异步也不要紧,我们还是来看实例,通过实例来理解才是最深刻的。
在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(
" 主线程方法结束 " );
        }
    }

可以看到我上面的注释行,去掉远程调用的注释,对下面的本地调用注释,编译后启动服务端,再启动客户端就是远程调用了。



异步调用结束,立即就能显示出结果,如果开启远程方法的话,可以看的更加清晰:
客户端:主线程方法开始-》服务端:异步方法开始-》服务端:异步方法结束-》客户端:结果是3-》客户端:主线程方法结束-》客户端:用了3.03125秒。

3、单向异步就是像同步调用方法那样调用方法,方法却是异步完成的,但是不能获得方法的返回值而且不能像同步方法那样取得所调用方法的异常信息!对于不需要返回信息的长时间方法,我们可以放手让它去干就行了:

远程对象:

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(
" 主线程方法结束 " );
        }
    }
}

这次我们仅仅只能在远程调试,我们先让异步方法去做,然后就放心的做主线程的事情,其他不管了。

运行结果我描述一下:
客户端:主线程方法开始-》服务端:异步方法开始-》服务端:异步方法结束-》客户端:主线程方法结束-》客户端:用了3.8秒。

上面说的三种方法,只是异步编程的一部分,具体怎么异步调用远程方法要结合实际的例子,看是否需要用到方法的返回和主线程方法的运行时间与远程方法运行时间等结合起来考虑,比如上述的WaitHandle也可以用轮询来实现:
while(Iar.IsCompleted==false) System.Threading.Thread.Sleep(10);总的来说远程对象的异步操作和本地对象的异步操作是非常接近。

还可以参考msdn相关文章:
http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpguide/html/cpconasynchronousprogrammingdesignpattern2.asp
原文地址:http://www.cnblogs.com/lovecherry/archive/2005/05/20/159784.html

 

 

本文转自温景良(Jason)博客园博客,原文链接:http://www.cnblogs.com/wenjl520/archive/2009/08/08/1541952.html如需转载请自行联系原作者

相关文章
|
2月前
|
Linux
vertx的学习总结4之异步数据和事件流
本文探讨了Vert.x中异步数据流的概念,包括事件流的抽象、背压机制的重要性,以及如何从流中解析协议数据,并通过文件流的示例代码展示了异步文件操作的处理方式。
53 3
vertx的学习总结4之异步数据和事件流
|
7月前
|
前端开发
muduo源码剖析之AsyncLogging异步日志类
AsyncLogging是muduo的日志,程序如果直接让文件写日志可能会发生阻塞,muduo前端设计了2个BufferPtr,分别是currentBuffer_和nextBuffer_,还有一个存放BufferPtr的vector(buffers_)。多个前端线程往currentBuffer_写数据,currentBuffer_写满了将其放入buffers_,通知后端线程读。前端线程将currentBuffer_和nextBuffer_替换继续写currentBuffer_。
84 0
|
前端开发 Java Maven
响应式编程实战(08)-WebFlux,使用注解编程模式构建异步非阻塞服务
响应式编程实战(08)-WebFlux,使用注解编程模式构建异步非阻塞服务
186 0
|
安全 中间件 Java
Semaphore&Future&动态代理(3)--分布式系统&中间件从入门到精通(七)
Semaphore&Future&动态代理(3)--分布式系统&中间件从入门到精通(七)
|
设计模式 Java Spring
【SpringBoot技术专题】「Async&Future」异步编程机制以及功能分析讲解
【SpringBoot技术专题】「Async&Future」异步编程机制以及功能分析讲解
181 0
|
iOS开发
iOS网络编程之三——NSURLConnection的简单使用
iOS网络编程之三——NSURLConnection的简单使用
169 0
iOS网络编程之三——NSURLConnection的简单使用
|
缓存 iOS开发
iOS网络编程之二——NSURLSession的简单使用
iOS网络编程之二——NSURLSession的简单使用
316 0
|
设计模式
akka设计模式系列-慎用ask
  慎用ask应该是Akka设计的一个准则,很多时候我们应该禁用ask。之所以单独把ask拎出来作为一篇博文,主要是akka的初学者往往对ask的使用比较疑惑。   "Using ask will send a message to the receiving Actor as with tell,...
2157 0