Performance Improvement for WCF Client Proxy Creation in .NET 3.5 and Best Practices

Introduction

In .NET 3.0 SP1, which will be shipped together with .NET 3.5, there is significant performance improvement in WCF client proxy creation. For BasicHttpBinding, the performance is close to that of ASMX proxy creation.

ASMX Proxy vs WCF Proxy

ASMX proxy is much simpler than WCF proxy. The former is a wrapper the type System.Web.Services.Protocols.SoapHttpClientProtocol. In ASMX world, the programming model is “horizontal” in two ways:

  • ·         There is no ServiceContract concept. The signatures of all service operations (WebMethod) are duplicated in the client proxy. The calls to those operations on the client side go through SoapHttpClientProtocol.Invoke. So there is no separation between service interface and the underlying message processing system.
  • ·         There is no clear channel stack. The SoapHttpClientProtocol wraps everything on the client-side. It directly invokes System.Net API HttpWebRequest.

Instead WCF provides a “vertical” programming model. You get the same rich programming features on the client side as that you get on the service-side. Internally WCF proxy is a .NET Remoting transparent proxy which is wrapped inside the type System.ServiceModel.Channels.ServiceChannel. The transparent proxy allows you to perform desired type casting and thus you can use the proxy and call service operations just like you are using the ServiceContract interface.

WCF Proxy Creation Cost

As pointed out in my last blog entry, there are two common ways of creating WCF client proxies (or channels):

1)     Using ClientBase<T> which is the default WCF support and you can use svcutil.exe tool to generate the proxy code.

2)     Using ChannelFactory<T>.CreateChannel().

A common pattern of using ClientBase<T> styled proxies is to perform creation/disposing on each call:

foreach (string msg in myList)

{

    // You may add try/catch block here ...

    HelloWorldProxy proxy = new HelloWorldProxy("MyEndpoint", new EndpointAddress(address)))

    proxy.Hello(msg);

    proxy.Close();

    // Error handling code here ...

}

Here HelloWorldProxy is auto-generated by svcutil.exe and it’s actually a subclass of ClientBase<IHelloWorld> with the ServiceContract type IHelloWorld.

In .NET 3.0, creating/disposing WCF client proxies is a very expensive operation for both approaches. It’s much worse than that for ASMX proxies. The approach 1) involves creating ChannelFactory<T> internally. Each proxy holds a ChannelFactory object as a private field. The lifetime of the ChannelFactory is fully controlled by the proxy. Approach 2) is much better since you have your own control of the ChannelFactory<T> object and thus you may only create it once and thus save the cost for further proxy creation.

Why is creating/disposing ChannelFactory so expensive? This is because it involves the following major operations:

  • Constructing the ContractDescription tree
  • Reflecting all of the required CLR types
  • Constructing the channel stack
  • Disposing all of the resources

In most cases, these data are identical between different proxies which are created in the same way.

In .NET 3.0 SP1, which will be shipped together with .NET 3.5, there are two major performance improvements in this area:

  • ·         ChannelFactory caching inside ClientBase<T>. This significantly improves the performance for approach 1).
  • ·         Channel management logic is improved and thus both 1) and 2) benefits from this.

With these improvements, creation of WCF proxie have quite comparable performance as ASMX ones.

Improvements

The idea of improving the performance of ClientBase<T> is simple: caching ChannelFactory objects. This is similar as the client type cache in ASMX proxy.

ChannelFactory Caching for ClientBase<T>

The key idea is to cache the ChannelFactory object at AppDomain level so that the lifetime of a ChannelFactory object is not controlled by the proxy. The cache is a most recently used (MRU) cache. The cache size is hard-coded as 32 so that the least used ChannelFactory objects are purged from the cache.

With the ChannelFactory cache, the rough process of creating a ClientBase<T> object is as following:

  • ·         In the constructor of ClientBase<T>, a lookup is performed to find a matched ChannelFactory in the cache.
  • ·         If found, the ref-count of the ChannelFactory is incremented. Otherwise, a new ChannelFactory is created based on the settings.
  • ·         Before the inner channel (the transparent proxy) of ClientBase<T> is created, the caching logic for the current ClientBase<T> can be disabled if other public properties (such as ChannelFactory, Endpoint, and ClientCredentials) are accessed.
  • ·         Once the innerchannel if created successfully, the ChannelFactory object for the ClientBase<T> is added to the cache if it’s not grabbed from the cache and caching is not disabled.
What is Matched ChannelFactory?

Did I say “matched” ChannelFactory in the last section? Yes, you have to make sure that you can differentiate different ChannelFactory objects based on the input settings from ClientBase<T>’s constructors. There are two types of constructors: those have Binding as a parameter and those don’t. Here are those that don’t:

  • ClientBase();
  • ClientBase(string endpointConfigurationName);
  • ClientBase(string endpointConfigurationName, string remoteAddress);
  • ClientBase(string endpointConfigurationName, EndpointAddress remoteAddress);
  • ClientBase(InstanceContext callbackInstance);
  • ClientBase(InstanceContext callbackInstance, string endpointConfigurationName);
  • ClientBase(InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress);
  • ClientBase(InstanceContext callbackInstance, string endpointConfigurationName, EndpointAddress remoteAddress);

For these constructors, all arguments (including default ones) are in the following list:

  • ·         InstanceContext callbackInstance
  • ·         string endpointConfigurationName
  • ·         EndpointAddress remoteAddress

As long as these three arguments are the same when ClientBase<T> is constructed, we can safely assume that the same ChannelFactory can be used. Fortunately, String and EndpointAddress types are immutable, i.e., we can make simple comparison to determine whether two arguments are the same. For InstanceContext, we can use Object reference comparison. The type EndpointTrait<TChannel> is thus used as the key of the MRU cache.

Here are the two constructors which have Binding as a parameter:

  • ClientBase(Binding binding, EndpointAddress remoteAddress);
  • ClientBase(InstanceContext callbackInstance, Binding binding, EndpointAddress remoteAddress);

Since Binding object is mutable, i.e., people can use it for one proxy, modify it and use it for another one, we can not safely detect whether there is a change to a binding object or not. Thus when the Binding is supplied in the constructors, the caching mechanism is disabled for that proxy.

Disabling caching

WCF supports extensibility in the way that people can change the settings of the ChannelFactory and the ContractDescription before the ChannelFactory is opened. Such change to a newly created proxy would prevent it from sharing the same ChannelFactory with other proxies. Same logic applies to other properties for the ClientBase<T>:

  • ChannelFactory
  • Endpoint
  • ClientCredentials

When any of these properties of ClientBase<T> is accessed before the inner channel is created and when ClientBase<T>.Open is called, the caching is disabled for this proxy. This is natural since you don’t want one proxy reuses the ChannelFactory for another proxy which has different contract or security settings.

Channel Management

Each channel that is created internally is added to the System.ServiceModel.Channels.CommunicationObjectManager. The performance of adding/removing an item from this class is improved in .NET 3.5. The fix was to switch from List<T> to Hashtable internally. This is why you will see performance improvement in approach 2) above.

Best Practices

Now that I have talked about the internals, I want to summarize how you can achieve best performance using WCF client proxies.

Reuse the same proxy

In many cases, you would want to reuse the same proxy. This has the best performance. It is especially true when you use security features since the initial security negotiation can have high cost.

Don’t forget to open the proxy explicitly before using it as I mentioned that in my previous blog entry.

Use proxy that enables caching

As mentioned above, you can either use ChannelFactory<T>.CreateChannel to create your proxy or you can use auto-generated proxies. If you use the latter, you need to be aware of the following in order to get ChannelFactory cached:

  • ·         Don’t use the constructors of the proxy that takes Binding as an argument.
  • ·         Don’t access the public properties ChannelFactory, Endpoint, and ClientCredentials of the proxy.
Disabling caching

If you really want to disable caching, you can simply do the reverse of above. For example, you can access the ChannelFactory property of the proxy before it is first used.

Proxy/Channel pooling

The last resort of achieving high performance is through proxy caching. In some scenarios, you may not want all threads to use the same proxy due to the following two possible reasons:

  • ·         The context of the channels does not allow multiple threads to access.
  • ·         There is some bottleneck in the Channel stack that hurts performance when a single proxy is used.

The logic of pooling can be from very simple to very complicated. Some ideas to keep in mind are as following:

  • ·         You need to implement the right synchronization logic for managing the proxies.
  • ·         You need to make sure the proxies are used equally. Sometimes, you may want to implement a round-robin pattern for the proxies.
  • ·         You need to handle exceptions and retries for the pool.
  • ·         The pool size needs to be limited and configurable.
  • ·         You may need to be able to create proxies even if when no proxy is available from the pool.

I don’t have a concrete example about why you need to implement the pool. If you have such a scenario, please do let me know.

reference:http://blogs.msdn.com/b/wenlong/archive/2007/10/27/performance-improvement-of-wcf-client-proxy-creation-and-best-practices.aspx

 

转载于:https://www.cnblogs.com/sanjia/archive/2011/03/20/performance-improvement-of-wcf-client-proxy-creation-and-best-practices.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于YOLOv9实现工业布匹缺陷(破洞、污渍)检测系统python源码+详细运行教程+训练好的模型+评估 【使用教程】 一、环境配置 1、建议下载anaconda和pycharm 在anaconda中配置好环境,然后直接导入到pycharm中,在pycharm中运行项目 anaconda和pycharm安装及环境配置参考网上博客,有很多博主介绍 2、在anacodna中安装requirements.txt中的软件包 命令为:pip install -r requirements.txt 或者改成清华源后再执行以上命令,这样安装要快一些 软件包都安装成功后才算成功 3、安装好软件包后,把anaconda中对应的python导入到pycharm中即可(不难,参考网上博客) 二、环境配置好后,开始训练(也可以训练自己数据集) 1、数据集准备 需要准备yolo格式的目标检测数据集,如果不清楚yolo数据集格式,或者有其他数据训练需求,请看博主yolo格式各种数据集集合链接:https://blog.csdn.net/DeepLearning_/article/details/127276492 里面涵盖了上百种yolo数据集,且在不断更新,基本都是实际项目使用。来自于网上收集、实际场景采集制作等,自己使用labelimg标注工具标注的。数据集质量绝对有保证! 本项目所使用的数据集,见csdn该资源下载页面中的介绍栏,里面有对应的下载链接,下载后可直接使用。 2、数据准备好,开始修改配置文件 参考代码中data文件夹下的banana_ripe.yaml,可以自己新建一个不同名称的yaml文件 train:训练集的图片路径 val:验证集的图片路径 names: 0: very-ripe 类别1 1: immature 类别2 2: mid-ripe 类别3 格式按照banana_ripe.yaml照葫芦画瓢就行,不需要过多参考网上的 3、修改train_dual.py中的配置参数,开始训练模型 方式一: 修改点: a.--weights参数,填入'yolov9-s.pt',博主训练的是yolov9-s,根据自己需求可自定义 b.--cfg参数,填入 models/detect/yolov9-c.yaml c.--data参数,填入data/banana_ripe.yaml,可自定义自己的yaml路径 d.--hyp参数,填入hyp.scratch-high.yaml e.--epochs参数,填入100或者200都行,根据自己的数据集可改 f.--batch-size参数,根据自己的电脑性能(显存大小)自定义修改 g.--device参数,一张显卡的话,就填0。没显卡,使用cpu训练,就填cpu h.--close-mosaic参数,填入15 以上修改好,直接pycharm中运行train_dual.py开始训练 方式二: 命令行方式,在pycharm中的终端窗口输入如下命令,可根据自己情况修改参数 官方示例:python train_dual.py --workers 8 --device 0 --batch 16 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 训练完会在runs/train文件下生成对应的训练文件及模型,后续测试可以拿来用。 三、测试 1、训练完,测试 修改detect_dual.py中的参数 --weights,改成上面训练得到的best.pt对应的路径 --source,需要测试的数据图片存放的位置,代码中的test_imgs --conf-thres,置信度阈值,自定义修改 --iou-thres,iou阈值,自定义修改 其他默认即可 pycharm中运行detect_dual.py 在runs/detect文件夹下存放检测结果图片或者视频 【特别说明】 *项目内容完全原创,请勿对项目进行外传,或者进行违法等商业行为! 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值