分享
 
 
 

(原创)一步一步学Remoting之五:异步操作

王朝asp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

一步一步学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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有