不管是Winform还是Web调用,都是可以对Webservice进行异步调用的。
方法有两种:
(1)Begin/End方法(虽然被丢弃)。
(2)事件驱动方法。
下面来具体谈谈这两种方法;
1、Begin/End方法
使用 Begin/End 模式实现进行异步方法调用的 Web 服务客户端
客户端如何知道何时调用 End 方法呢?根据 .NET Framework 的定义,有两种方法可以使客户端确定这一点:
客户端调用方式1等待方法:使用 WaitHandle 类的方法之一使客户端等待方法完成。
客户端调用方式2回调方法:向 Begin 方法传递一个回调函数,在该方法完成处理后再调用该函数来检索结果。
注意:无论客户端选择两种方法中的哪一种与 Web 服务进行异步通信,收发的 SOAP 消息都与通过同步代理方法生成的 SOAP 消息相同。也就是说,仍然只有一个 SOAP 请求和 SOAP 响应通过网络发送和接收。代理类通过使用与客户端调用 Begin 方法时使用的线程不同的线程来处理 SOAP 响应,从而实现该目的。因此,在代理类接收和处理 SOAP 响应时,客户端可以在其线程上继续执行其他工作。
webservice代码:
客户端调用方式1(Begin/End 模式的回调方法):
解说(解说来自MSDN):
<!--[if !supportLists]-->
定义实现 AsyncCallback 委托的回调函数。
public static void FactorizeCallback(IAsyncResult ar)
<!--[if !supportLists]-->
实例化 AsyncCallback 委托。
<!--[endif]-->
AsyncCallback cb = new AsyncCallback(TestCallback.FactorizeCallback)
<!--[if !supportLists]--><!--[endif]-->调用 Begin 方法,将回调函数作为第二个参数传递,将提供状态的对象(在本示例中是 PrimeFactorizer 的客户端实现)作为第三个参数传递。
IAsyncResult ar = pf.BeginFactorize(factorizableNum, cb, pf)
<!--[if !supportLists]--><!--[endif]-->在 Begin 方法返回的 IAsyncResult 上检查 IsCompleted 属性。如果客户端已收到服务器的响应,该值将设置为 true。
<!--[if !supportLists]--><!--[endif]-->在回调函数中访问状态对象。IAsyncState 参数的 AsyncState 属性将该对象作为第三个参数传递给 Begin 方法。
PrimeFactorizer pf = (PrimeFactorizer) ar.AsyncState
<!--[if !supportLists]--><!--[endif]-->在回调函数中,对上一步中获取的状态对象调用 End 方法。
long[] results = pf.EndFactorize(ar)
客户端调用方式2(Begin/End 模式的等待方法):
解说(解说来自MSDN):
WaitHandle 类实现下列支持等待同步对象得到信号通知的方法:WaitOne、WaitAny 和 WaitAll。当同步对象得到信号通知时,表示等待指定资源的线程此时可以访问该资源了。Web 服务客户端通过 Begin 方法返回的 IAsyncResult 对象的 AsyncWaitHandle 属性,来访问 WaitHandle 对象。
具体做法:
<!--[if !supportLists]-->1、 <!--[endif]-->Web 服务客户端调用所生成的代理类的 Begin 方法。
IAsyncResult ar = pf.BeginFactorize(factorizableNum, null, null)
<!--[if !supportLists]-->2、 <!--[endif]-->Web 服务客户端通过返回的 IAsyncResult 的 AsyncWaitHandle 属性来访问 WaitHandle 对象。
ar.AsyncWaitHandle.WaitOne()
<!--[if !supportLists]-->3、 <!--[endif]-->等待方法返回后,客户端调用 End 方法来获取结果。
results = pf.EndFactorize(ar)
2、事件驱动方法
解说:
Web 服务代理类中的每个 Web 方法都具有一个异步的对应版本。代理类自动生成每个 Web 方法的异步方法和对应事件。当异步方法被调用时,将在另一个线程上执行,并在返回时引发对应的事件。可以为异步方法的对应事件创建一个处理程序,从而 在返回时执行代码。
此模型可以简化生成多线程应用程序的过程,因为不必自己实现复杂的多线程代码。
具体做法:
<!--[if !supportLists]-->1、 <!--[endif]-->创建MethodCompleted 事件。
private void HelloWorldCompleted(Object sender,
localhost.HelloWorldCompletedEventArgs Completed)
{
// Insert code to implement the method here
}
<!--[if !supportLists]-->2、 <!--[endif]-->向该事件的处理程序列表添加 MethodCompleted 事件处理程序。
myWebService.HelloWorldCompleted += new localhost.HelloWorldCompletedEventHandler(HelloWorldCompleted)<!--[if !supportLists]-->3、 <!--[endif]-->使用该方法的 MethodAsync 形式调用 Web 方法.
HelloWorldAsync()
二.异步调用的优势:异步出来的新线程,.NET也是不允许的,所以别想钻空子,下面可以很容易想到,回收分为2种情况:主动回收和被动回收,主动回收就是,去监视那个线程,并且等待,当异步方法完成了,就把异步线程回收,焦点回归主线程,BeginInvoke之后又EndInvoke,如果在EndInvoke的时候,该异步线程没有完成操作,那么整个程序,包括主线程,又在阻塞了,又会出现界面的情况。要想解决这个问题,就使用“被动回收”方式,其中一个重要的办法就是“异步回调”。 核心有二: A、 用回调函数,异步结束后,自动调用此回调函数。 B、 而不在主线程中手工等待异步结束,如上两例中在主线程中调用EndInvoke。此种方法,是在回调函数中调用EndInvoke的。
同步/非同步本来是IO方面的概念,不过我们可以把函数乃至各种RPC理解成一种IO设备,这样就可以把这两个词扩展到函数调用领域了。同步的函数调用指的是当函数调用返回的时候,需要函数干的事已经完成。而异步调用则没有这个保证,工作可能在函数返回前完成,也可能在之后某个时刻。同步/异步很容易跟阻塞/非阻塞混淆起来。严格说起来它们是有区别的:阻塞的调用指的是当前提满足的时候干活,不满足的时候等到满足为止;非阻塞则是前提满足的时候干活,不满足的时候立刻返回错误。不过很多时候,异步调用会表现出“非阻塞”的特征——不是真正的非阻塞,但由于很快返回(一般小于1us),所以在某种程度上可以被视为非阻塞(耗时短)的调用。在很多接口描述文档里,非阻塞其实说的是异步。在函数调用领域,一般情况下没有必要去严格区分异步和非阻塞。说来奇怪,我们天生就懂异步——比如你问隔壁几点的时候,不会两眼无神,整个人都斯巴达,等到回答后才恢复神智。但是编写/使用异步函数却会让大多数程序员感到痛苦不堪。为什么我们需要异步调用这个反人类的东西?本质原因在于有时候我们需要用少数线程来执行多个并行route,同时又要求低响应延迟。对于熟悉图形界面开发的人来说,应该都知道不能在事件响应函数里执行长耗时的任务,否则在函数执行完之前,整个界面将失去响应。这是因为大多数图形界面sdk都是用一个线程(为什么不用多个线程?还真有人试过,好像记得是早期的AWT,结果满地找牙。现在公认的最佳实践就是用唯一线程)来处理各种输入,产生事件并调用响应函数。如果这个线程在进行某个长时间的操作,界面失去响应就不足为奇了。又比如select/epoll/iocp服务器,采用这些API的服务,一个网络线程往往同时服务成千上万个连接。如果某个连接上的处理花费了过长时间,则这段时间内其他连接也同样无法得到响应。客户端界面失去响应1-2s,一般还是可以接受的,但服务器(比如网游)就不大好说了。所以需要避免在事件处理线程中执行会阻塞或者耗时过长的操作。为了这个目的,将同步调用转换成异步调用是最常用手段了。其实同步调用与异步调用很容易进行转换:如果想要把一个同步调用转换成异步调用,只需要一个线程或一组线程加上消息队列即可。根据异步调用处理工作完成的方式,可以将其细分成三类:1)甩手掌柜,不管;2)做个标记,让调用者需要时询问。“帮我买个馒头”- “馒头买好了没有?”- “馒头买好了没有?”3)直接回调,如“帮我买个馒头,买好后放在我包里”。下面的代码演示了如何将一个同步调用转换成后两类异步调用(第一类太没难度,不够niubility,忽略)===================体位2的分隔线=====================#include <iostream>#include <string>#include <queue>#include <boost/bind.hpp>#include <boost/thread.hpp>#include <windows.h> //只用到Sleep函数using namespace stdstring somefuncMaybeBlock(){string strgetline(cin, str)return str //如果是未采用隐式数据共享的std实现,这句话比较低效,但无妨,此例只是演示体位变换}欢迎分享,转载请注明来源:夏雨云
评论列表(0条)