你的位置:首页 > 软件开发 > ASP.net > 第五讲:异步操作

第五讲:异步操作

发布时间:2016-05-13 21:00:19
代码https://yunpan.cn/cPns5DkGnRGNs 密码:3913 我们接着上一张的内容去讲,上一张的最后,看到了我们的程序报错了。 这里我们解释一下为什么报错,为什么会出现死锁呢?异常:究其本质,这是一个死锁导致的异常,由于默认的情况是服务 ...

代码

https://yunpan.cn/cPns5DkGnRGNs   密码:3913

 


 

我们接着上一张的内容去讲,上一张的最后,看到了我们的程序报错了。 

这里我们解释一下为什么报错,为什么会出现死锁呢?

异常:究其本质,这是一个死锁导致的异常,由于默认的情况是服务按Single并发模式执行(在服务器执行过程中,服务对象只能被一个get='_blank'>线程访问。WCF通过加锁的机制保证服务对象的独占性使用,也就是说在服务执行开始时会对服务对象加锁,该锁在服务操作结束之后释放)

 

在Add操作执行的过程中,服务端会回调客户端操作进行运算结果的显示工作。

如果回调采用单向操作:

回调请求一经发出便会立即返回,不需要等待服务端的反馈,操作可以继续得到执行,直到操作正常结束。而另一方面的服务端,当调用操作在客户端正常执行后,需要反馈回到服务端所以试图访问操作的时候,发现对象被服务操作执行的线程锁定,所以他会等待服务操作执行完成后将锁释放。这样,服务操作需要等待回调操作进行正常的返回以便执行后续操作,而回调操作只有等待服务操作执行完成之后将锁释放才可以访问。所以就造成了死锁状态。

通俗讲就是  因为客户端第一次调用服务端的Add方法的线程正在执行并且执行到了等待客户端的反馈信息,就这样一直的等待,资源不会被释放以至于处于锁定状态,而客户端也执行完成了相关操作,需要进行反馈服务端信息,但是服务端一直处于锁定状态,而无法再次请求。两边就产生了 矛盾。所以死锁了。

 


 

 

那么怎么解决上面的问题呢?

 

使用多线程或者异步操作

 

多线程与异步操作

按照操作执行所需要的资源类型,我们可以将操作分为CPU绑定型操作和I/O操作。对于前者,操作的执行主要利用CPU进行密集的计算:而对于后者,大部分的操作处理时间花在I/O操作处理,比如访问数据库,文件系统,网络资源等。对于I/O的操作,我们可以充分利用多线程的机制,让多个操作在自己的线程并发执行,从而提高系统性能和响应能力。服务调用就是典型的I/O操作,所以多线程在服务调用中具有广泛的应用。

 

如果按照异步操作发生的位置,可以将WCF应用的异步操作分为下面2种情况:

1:异步信道调用:

  客户端通过绑定创建的信道向服务端发送消息,从而实现了对服务的调用。客户端也可以通过代理对象异步地调用信道,从而实现异步服务调用。

2:单向(One-Way)消息交换   (这一种我们第四讲已经说过了,只是没有点透,这里说单向消息交换   与 第一种  异步信道  其实是  异曲同工 的效果   )

  客户端信道通过单向的消息交换模式向服务端发送消息,消息一旦抵达传输层马上返回,从而达到异步服务调用的效果。

 

 

 

 

我们重点说说  异步信道的调用:

为了方便客户端进行异步的服务调用,最简单的方式是通过添加服务引用的方式来创建(第一讲我们说过)。通过该方式来创建异步服务代理,创建的方式只需要在添加服务引用对话框中点击“高级”按钮,便会填出一个“服务引用设置”对话框,勾选“生成异步操作”复选框即可。

 

[ 5-01 ]

第五讲:异步操作

 

[ 5-02 ]

第五讲:异步操作

 

不管 勾不勾选 " 允许生成异步操作 " 的复选框   都会生成一个继承自ClientBase<TChannel>的类,但 勾选后 所不同的是,该类中会多出一些与异步服务调用相关的成员。 在具体通过服务代理进行异步服务调用的时候,可以采用不同的调用方式,不仅可以采用参数典型的BeginXxx和EndXxx的形式,也可以采用回调的形式,还可以采用事件注册的方式。

 

例如:我们的契约中有个Add的方法,如果勾选了 " 允许生成异步操作 "  的复选框  就会多出一个  BeginAdd  和   EndAdd  的方法,这两个方法就是异步操作的方法。

 


 

 

 

我们做一个异步服务调用的小Demo,代码还是在 云盘,自己去找:

 

说明一下,异步服务调用 的发起者 一定是 客户端,所以  其它地方 不需要额外说明,与之前一样不变的代码

 

[ 5-03 ]

第五讲:异步操作

 

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.ServiceModel; 6  7  8 namespace Client 9 {10   class Program11   {12     static void Main(string[] args)13     {14 15 16       //必须先通过 先 添加服务引用17 18       //通过BeginXxx/EndXxx进行异步服务调用19       //在调用BeginAdd方法后,可以做一些额外的处理工作,这些工作将会和Add服务操作的调用并发地运行,最终的运算结果通过EndAdd方法得到20 21       //创建 服务引用的 代理22       ServiceCalculator.CalculatorClient proxy = new Client.ServiceCalculator.CalculatorClient();23       //异步操作24       IAsyncResult asynResult = proxy.BeginAdd(1, 2, null, null);25       //得到返回的结果26       double result = proxy.EndAdd(asynResult);27       proxy.Close();28       Console.WriteLine("x+y={2} when x={0} and y={1}", 1, 2, result);29       Console.Read();30 31 32       /*33        其实上面的方法并不好34        是当EndAdd方法被执行的时候 如果异步执行的Add方法(也就是调用服务端的方法)还没有执行结束的话,在EndAdd方法这里将会阻塞当前线程(这个当前的线程指的是 客户端的线程)35        并等待异步方法(调用服务端的Add方法)的结束,这样往往不能起到多线程并发执行应有的作用。我么真正希望的是在异步执行结束后自动回调设定的操作,这样就可以采用回调的方式36        来实现这样的机制。37       38        去看第二种异步调用的方法39       40       */41 42 43     }44   }45 }

原标题:第五讲:异步操作

关键词:异步

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。