做网站卖酒营销推广运营
做网站卖酒,营销推广运营,建e网网址是多少,wordpress图标方块在[第1篇]中#xff0c;我们介绍了WCF关于实例管理一些基本的知识点#xff0c;包括InstanceContext、InstanceContextMode、已经如何通过ServiceBehaviorAttribute应用不同的实例上下文模式给不同的服务。在[第1篇]中#xff0c;对WCF采用的三种不同实例上下文模式进行了简…在[第1篇]中我们介绍了WCF关于实例管理一些基本的知识点包括InstanceContext、InstanceContextMode、已经如何通过ServiceBehaviorAttribute应用不同的实例上下文模式给不同的服务。在[第1篇]中对WCF采用的三种不同实例上下文模式进行了简单的比较本篇的重点方法对单调PerCall模式为进行详细介绍。 在单调Per-Call实例上下文模式下WCF总是创建一个新的服务实例上下文处理接收到的每一个服务调用请求并在服务操作执行结束后回收服务上下文和服务实例。换句话说单调服务实例上下文模式使服务实例上下文的生命周期与服务调用本身绑定。我们首先来介绍单调模式下服务实例上下文具体有怎样的生命周期。 一、 单调模式下的服务实例上下文提供机制 对于单调模式服务实例的生命周期大体上可以看成服务操作执行的生命周期。服务实例在服务操作执行前被创建在操作完成之后被回收。下面的列表揭示了在单调模式下对于每一次服务调用请求WCF的整个服务实例激活过程 WCF服务端接收到来自客户端的服务调用请求 通过实例上下文提供者InstanceContextProvider对象试图获取现有服务实例的实例上下文对于单调模式返回的实例上下文永远为空 如果获取实例上下文为空则通过实例提供者IntanceProvider创建服务实例封装到新创建的实例上下文中 通过InstanceContext的GetServiceInstance方法获取服务实例对象借助操作选择器OperationSelector选择出相应的服务操作最后通过操作执行器OperationInvoker对象执行相应的操作方法 操作方法执行完毕后关闭被卸载InstanceContext对象。在此过程中会调用InstanceProvider对象释放服务实例如果服务类型实现了接口IDisposable则会调用Disposable方法 服务实例成为垃圾对象等待GC回收。 对于上述列表中提到的InstanceContextProvider、InstanceProvider等重要的对象以及相关的实现机制将在本系列后续的部分进行单独讲解。为了加深读者的理解这里通过一个简单的例子来演示在单调模式下服务实例的整个激活流程。 二、 实例演示单调模式下服务实例的生命周期 本案例依然沿用典型的4层结构和计算服务的场景下面是服务契约和具体服务实现的定义。在CalculatorService类型上通过ServiceBehaviorAttribute特性将实例上下文模式设为单调Per-Call模式。为了演示服务实例的创建、释放和回收我们分别定义了无参构造函数终止化器Finalizer以及实现的接口IDisposable并在所有的方法中输出相应的指示性文字以便更容易地观测到它们执行的先后顺序。 1: using System.ServiceModel; 2: namespace Artech.WcfServices.Contracts 3: { 4: [ServiceContract(Namespacehttp://www.artech.com/)] 5: public interface ICalculator 6: { 7: [OperationContract] 8: double Add(double x, double y); 9: } 10: } 1: using System; 2: using System.ServiceModel; 3: using Artech.WcfServices.Contracts; 4: namespace Artech.WcfServices.Services 5: { 6: [ServiceBehavior(InstanceContextMode InstanceContextMode.PerCall)] 7: public class CalculatorService : ICalculator, IDisposable 8: { 9: public CalculatorService() 10: { 11: Console.WriteLine(Service object is instantiated.); 12: } 13: ~CalculatorService() 14: { 15: Console.WriteLine(Service object is finalized.); 16: } 17: 18: public void Dispose() 19: { 20: Console.WriteLine(Service object is disposed.); 21: } 22: public double Add(double x, double y) 23: { 24: Console.WriteLine(Operation method is invoked.); 25: return x y; 26: } 27: } 28: } 为了演示GC对服务实例的回收在进行服务寄宿的时候通过System.Threading.Timer使GC每隔10毫秒强制执行一次垃圾回收。 1: using System; 2: using System.ServiceModel; 3: using System.Threading; 4: using Artech.WcfServices.Services; 5: namespace Artech.WcfServices.Hosting 6: { 7: public class Program 8: { 9: private static Timer GCScheduler; 10: 11: static void Main(string[] args) 12: { 13: GCScheduler new Timer( 14: delegate 15: { 16: GC.Collect(); 17: }, null, 0, 100); 18: using (ServiceHost serviceHost new ServiceHost(typeof(CalculatorService))) 19: { 20: serviceHost.Open(); 21: Console.Read(); 22: } 23: } 24: } 25: } 通过一个控制台应用程序对服务进行成功寄宿后客户端通过下面的代码使用相同的服务代理对象进行两次服务调用。 1: using System; 2: using System.ServiceModel; 3: using Artech.WcfServices.Contracts; 4: namespace Artech.WcfServices.Clients 5: { 6: class Program 7: { 8: static void Main(string[] args) 9: { 10: using (ChannelFactoryICalculator channelFactory new ChannelFactoryICalculator(calculatorservice)) 11: { 12: ICalculator calculator channelFactory.CreateChannel(); 13: Console.WriteLine(x y {2} when x {0} and y {1}, 1, 2, calculator.Add(1, 2)); 14: Console.WriteLine(x y {2} when x {0} and y {1}: {3}, 1, 2, calculator.Add(1, 2)); 15: } 16: } 17: } 18: } 从运行后服务端的输出可以看出对于两次服务调用请求服务端先后创建了两个服务实例在操作方法成功执行后Dispose方法得以执行。而终止化器Finalizer是被GC在后台执行的所以执行的时机不能确定。不过有一点可以从中得到证实当服务操作执行时服务实例变成了“垃圾”对象并可以被GC回收以腾出占据的内存空间。 Service object is instantiated. Operation method is invoked. Service object is disposed. Service object is instantiated. Operation method is invoked. Service object is disposed. Service object is finalized. Service object is finalized. 三、 服务实例上下文的释放 如果服务实例须要引用一些非托管资源比如数据库连接、文件句柄等须要及时将其释放。在这种情况下我们可以通过实现IDisposable接口在Dispose方法中进行相应的资源回收工作。在单调实例上下文模式下当服务操作执行时Dispose方法会自动被执行这一点已经通过上面的案例演示得到证实。 对于实现了IDisposable接口的Dispose方法有一点值得注意的是该方法是以与操作方法同步形式执行的。也就是说服务操作和Dispose方法在相同的线程中执行。认识这一点很重要因为无论采用怎样的实例模式在支持会话Session的情况下如果服务请求来自于同一个服务代理服务操作都会在一个线程下执行。对于单调模式就会出现这样的问题由于Dispose方法同步执行的特性如果该方法是一个比较耗时的操作那么来自于同一个服务代理的服务后续调用请求将不能得到及时执行。WCF只能在上一个服务实例被成功释放之后才能处理来自相同服务代理的下一个服务调用请求。为了让读者体会到同步方式释放服务实例在应用中的影响并证明同步释放服务实例的现象我们对上面的案例略加改动。 在CalculatorService中通过线程休眠的方式模拟耗时的服务实例释放操作5秒。在Dispose和Add方法中除了输出具体操作名称之外还会输出当前的线程ID和执行的开始时间代码如下所示。 1: [ServiceBehavior(InstanceContextMode InstanceContextMode.PerCall)] 2: public class CalculatorService : ICalculator, IDisposable 3: { 4: public void Dispose() 5: { 6: Console.WriteLine(Time: {0}; Thread ID: {1}; Service object is disposed., DateTime.Now, Thread.CurrentThread.ManagedThreadId); 7: Thread.Sleep(5000); 8: } 9: public double Add(double x, double y) 10: { 11: Console.WriteLine(Time: {0}; Thread ID: {1}; Operation method is invoked., DateTime.Now, Thread.CurrentThread.ManagedThreadId); 12: return x y; 13: } 14: } 在客户端我们创建两个不同的服务代理通过ThreadPool分别对它们进行2次异步调用。下面是相关的服务调用代码。 1: using (ChannelFactoryICalculator channelFactory new ChannelFactoryICalculator(calculatorservice)) 2: { 3: ICalculator calculator channelFactory.CreateChannel(); 4: ThreadPool.QueueUserWorkItem(delegate 5: { 6: Console.WriteLine({3}: x y {2} when x {0} and y {1}, 1, 2, calculator.Add(1, 2), DateTime.Now); 7: }); 8: ThreadPool.QueueUserWorkItem(delegate 9: { 10: Console.WriteLine({3}: x y {2} when x {0} and y {1}, 1, 2, calculator.Add(1, 2), DateTime.Now); 11: }); 12: Console.Read(); 13: } 从客户端和服务端输出结果的比较我们可以清晰地看出基于相同服务代理的操作方法和Dispose方法都执行在相同的线程下线程ID为12并且两次服务操作的间隔为服务实例释放的时间5秒。由于服务操作和Dispose方法的同步执行导致服务端忙于释放上一个服务实例而不能及时处理来自相同服务代理的下一个服务调用请求。 客户端 3/6/2009 71234 PM: x y 3 when x 1 and y 2 3/6/2009 71239 PM: x y 3 when x 1 and y 2 服务端 Time: 3/6/2009 71234 PM; Thread ID: 12; Operation method is invoked. Time: 3/6/2009 71234 PM; Thread ID: 12; Service object is disposed. Time: 3/6/2009 71239 PM; Thread ID: 12; Operation method is invoked. Time: 3/6/2009 71239 PM; Thread ID: 12; Service object is disposed. 关于服务实例的同步执行机制还有一点需要说明是在Dispose方法中可以得到当前OperationContext而OperationContext在会话Per-Session实例上下文模式下是不可得的。 四、单调模式与可扩展性 在单调模式下如果不考虑GC对垃圾对象回收的滞后性服务实例的数量可以看成是当前正在处理的服务调用请求的数量。相关的资源能够在服务操作执行完毕之后得到及时回收通过实现IDisposable接口将资源回收操作实现在Dispose方法中。所以单调模式具有的优势是能够最大限度地发挥资源的利用效率避免了资源的闲置和相互争用。 这里的资源不仅仅包括服务实例本事占据的内存资源也包括服务实例直接或间接引用的资源。由于单调模式采用基于服务调用的服务实例激活和资源分配方式所以服务实例或被分配的资源自始至终都处于“工作”状态不会造成资源的闲置。服务实例在完成其使命之后能够对资源进行及时的释放被释放的资源可以及时用于对其他服务请求的处理。 我们将单调模式和后面要讲的会话模式作一个对比后者采用基于服务代理的实例激活和生命周期管理。也就是说在不考虑WCF闲置请求策略当服务实例在超出某个时间段没有被使用的情况下WCF将其清理的情况下服务实例的生命始于通过服务实例进行第一次服务调用或者调用Open方法开启服务代理之时服务代理的关闭会通知WCF服务端框架将对应的服务实例进行释放。举一个极端的例子服务实例在存续期间需要引用一个非托管资源比如是数据库连接假设最大允许的并发连接为100。现在先后100个客户端或者服务代理进行服务调用请求毫无疑问100个服务实例会被创建并同时存在于服务端的内存之中并且每一个服务实例引用一个开启状态的数据库连接那么当来自第101个客户端服务调用请求抵达时将得不到处理除非在它的超时时限到达之前有一个客户端自动将服务代理关闭。 但是对于相同的场景如果采用单调的模式就能应付自如因为在每次服务调用之后数据库的连接可以及时地得到关闭和释放。 对于单调模式很多读者一开始就会心存这样的疑问服务实例的频繁创建对性能不会造成影响吗在前一章中我们就说过高性能Performance和高可扩展性Scalability是软件设计与架构中永远不可以同时兼顾的原因很简单高性能往往需要充足的资源高扩展性又需要尽可能地节约资源。所以我们才说软件设计与架构是一项“权衡”的艺术我们的目的不是将各个方面都达到最优因为这是不可能实现的任务我们须要做的只是找到一个平衡点使整体最优。关于高扩展性和性能之间的平衡关系我们很难有一个适合所有场景的黄金法则这需要对具体场景的具体分析。 较之会话模式单调模式能够处理更多的并发客户端提供更好的吞吐量Throughput。对于量化我们的服务到底能够处理多少客户端Juval Lowy在其著作《Programming WCF》中提出了这样一项经验性总结在一个典型的企业应用中并发量大概是所有客户端数量的1%高并发情况下能达到3%也就是如果服务端能够同时维持100个服务实例那么意味着能为10 000个客户端提供服务。 关于服务实例的创建过程其中会使用到诸如反射这样的相对影响性能的操作但是在WCF应用中真正影响性能是操作时信道的创建和释放。服务实例的激活和它们比起来可以说是微不足道。但是如果在应用中出现对基于相同服务代理的频繁调用比如服务调用放在一个For循环中调用上百次服务实例的创建带来的性能损失就不能不考虑了。 作者Artech 出处http://artech.cnblogs.com 本文版权归作者和博客园共有欢迎转载但未经作者同意必须保留此段声明且在文章页面明显位置给出原文连接否则保留追究法律责任的权利。 转载于:https://www.cnblogs.com/artech/archive/2009/11/09/1598695.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/87049.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!