前几天用WCF做项目时发现了一个效率问题,由于系统对效率要求较高,困扰了很长时间终于将问题解决了,写下来为以后的兄弟们参考,第一次写博客有不准确的地方还望同行们多喷多指点,先行谢过啦...

问题场景是这样的,我上传很多数据到服务器端,测试用的是100万条,由于服务器端需要对数据筛选并过滤,那么就将数据驻留在内存中,在处理完以后才写入到文件,需要的时候再从文件中读取出来,当然向文件写入和读取都是单独的线程来并发执行的...就是这样看似谁都不影响谁的完美策略竟然导致后续Server端接收WCF请求的延迟,并不是服务方法的内部有多复杂,而是请求就不能立即进入响应方法中...困扰了三天之后也查阅了很多网上资料终于找到了原因,原因是我数据存到Server端以后因为某些需要又用了一个线程把数据挪到另外一个内存缓存中,按理说只是多占些内存而已不应该影响接收请求的速度啊,其实想来想去除了多占了很多内存以外还多开了好几个线程,而且伴有大量的内存到文件的IO写入写出,就这样造成了线程开启的延迟,其实WCF的一次请求也是开启一个线程响应的,这是我这次总结出来的,如果有不准确的地方希望兄弟们给指正,再次感谢

顺便总结一下WCF效率优化设置的常规思路:

1、针对ServerHost端能接收的最大请求数量限制

在服务端设置ServiceHost,如:

1 host.Description.Behaviors.Add(new ServiceThrottlingBehavior()
2 {
3 MaxConcurrentInstances = 2000,
4 MaxConcurrentCalls = 2000,
5 MaxConcurrentSessions = 2000
6 }); 

2、针对Server端服务对象的管理及并发方式

设置服务的InstanceContextMode 及ConcurrencyMode 特性,设置方法是在实现服务契约的类上面用如下特性:

1 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
2 ConcurrencyMode = ConcurrencyMode.Multiple,
3 UseSynchronizationContext=false)]
4 public class MyService : IInterface{...}

说明:

(1)InstanceContextMode.PerCall表示每接收一个新的请求WCF都会新建一个服务实例来响应,这样本质不同请求的响应就是并发执行的

(2)将ConcurrencyMode设置为ConcurrencyMode.Multiple也是为了保险起见,个人认为这个多线程访问只有在InstanceContextMode.Single的时候也就是服务端针对每个请求都是一个对象响应的时候才谈得上多线程并发访问,因为InstanceContextMode.PerCall每个请求都是不同实例响应的,人家本来就是并发的

(3)如果不需要WCF服务内部帮你协调同步,那么设置UseSynchronizationContext=false,以后有多线程共享数据自己拿Lock去控制,我就是这么干的,因为我Lock的东西跟WCF没啥关系

3、针对首次访问速度很慢,以后访问速度快的问题

如果是用的类似HttpBasicBinding,访问服务端时首次很慢,可以考虑将binding的useDefaultWebProxy设置为"false",如果是用的类似NetTcpBinding,是没有这个属性的,这个属性默认是true,意思是在wcf客户端向Server端请求的时候总是尝试先查找代理,找不到再去直接连接,如果您的服务端确定的话,干脆直接连接算了,不让客户端再去找代理,设置为false得了...

4、针对WCF串行处理造成的延迟

默认WCF的代理都是自动打开的,即使您将ConcurrencyMode设置为Multiple,WCF依旧会以串行的而不是并行的方式响应,因为选择自动打开代理时,多个请求同时来到服务端,服务端会对请求进行排序等待且执行反序列化等,等这些都执行完了才会并发执行,这就造成了有先有后执行,既然是这样我们就不要WCF自动打开代理,而是我们手动的显示打开,具体方法如:((ICommunicationObject)client).Open();

(大家可以看看这个博客,我是在这里学到的:http://www.cnblogs.com/tyb1222/archive/2012/05/23/2515535.html)

5、WCF接收请求本质上也是开启一个线程来响应client请求的,那么就涉及到windows线程池,一般线程池虽然可以通过ThreadPool.SetMinThreads方法设置最小的线程数量,但是系统内部其实对空闲线程过16s就清理一次的(即使你现在的活动线程没有达到最小的线程池数量),只留一个空闲线程接收请求,如果刚刚清理完线程池而且这个空闲线程又刚好正接受请求的时候又来了一个新的请求,这时候CLR就会重新new一个线程,这时就会消耗一些时间,而且消耗时间的长短是时随机的视系统情况而定(这个问题据说.net 4.0还有),为了防止这些情况发生就需要时刻提醒Windows多留出一个空闲的线程别被回收以备随时调用,我们首先想到的就是定时提醒,但是如果每提醒一下就新建一个线程那么以后线程会越来越多cpu就不用干别的了,在那里只切换线程就够它忙活一阵子了,好在系统有更好的机制叫完成端口(IOCP),这个东西大家可以去网上搜搜,说的都比我好多了,个人理解这种机制说白了就是有一个公共的消息队列和几个特定的线程,您cpu有几核就会有几个线程对应,它能保证空闲的cpu内核有空闲的线程,而且也不会没有数量限制的新建线程,说白了就是您往完成端口发东西就会激活一个线程...因此我们要做的是就是定时往完成端口队列中写点东西,让那个队列去通知完成端口开辟出线程来,而且线程的回调方法什么都不做,说白了就是为了打开一个空闲的线程留给新的请求调用,节约时间,具体的实现方法如下(注:第5条观点及代码引自http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-does-wcf-become-slow-after-being-idle-for-15-seconds.aspx,建议大家去看看,虽然是英文的,写的可比我好多了,哈):

 1 static ManualResetEvent s_dummyEvent;
 2
 3 static RegisteredWaitHandle s_registeredWait;
 4
 5 /// <summary>
 6 /// 函数功能:每隔0.5秒都向IO完成端口发送一个空的数据包,进而激活一个空闲的线程,
 7 /// 保证时刻有一个空闲的线程来响应,这样wcf就避免请求因为新建线程延时了
 8 /// 备 注:防止.net线程池每16秒回收只留一个线程的情况发生
 9 /// </summary>
10 public static void DoWorkaround()
11 {
12 // Create an event that is never set
13
14 //创建一个永远都不启动的事件
15 s_dummyEvent = new ManualResetEvent(false);
16
17 // Register a wait for the event, with a periodic timeout. This causes callbacks
18 // to be queued to an IOCP thread, keeping it alive
19
20 //注册一个等待时间,每500ms注册一次,这样针对完成端口线程队列的回调会保证完成端口线程的活跃(英文不好,大家忍下吧)
21 s_registeredWait = ThreadPool.RegisterWaitForSingleObject(
22 s_dummyEvent,
23 (a, b) =>
24 {
25 // Do nothing
26 },
27 null,
28 500,
29 false);
30 }

写完上边的这个方法在代码中那里调用一下就行了...我修改了自己的程序结构以后那个请求延迟的问题没有了,思来想去我的问题应该是大量的IO线程导致的...

以上就是我总结出来的几点优化思路,希望能对其它兄弟有帮助,有不足的地方希望同行们多多指正

转载于:https://www.cnblogs.com/Taburensheng/p/5261374.html

WCF优化的几个常规思路相关推荐

  1. c语言五子棋人工智能算法,五子棋人工智能算法实现研究,优化五子棋智能算法的思路...

    五子棋是一种两人对弈的纯策略型棋类游戏,是起源于中国古代的传统黑白棋种之一.现代五子棋日文称之为"连珠",英译为"Renju",英文称之为"Goban ...

  2. 优化-处理大量定时任务的思路

    HashedWheelTimer-高效处理大量定时任务 背景 业务需要,要对app用户做个30s离线的功能,即:用户自登录开始,30s内无操作及下线. 常规思路1(单定时器轮询) 用户登录时用关联数组 ...

  3. C/C++编程笔记:输入输出的优化,你还为思路正确却TLE而烦恼吗?

    你还在为思路正确却TLE而烦恼吗? 我也没办法,谁让你是一枚蒟蒻呢 今天,本人给被TLE折磨的死去活来的各位介绍一个专治TLE的法宝: 此乃江湖一直流传着的 输入输出优化!!! 输入优化函数: 输出优 ...

  4. 一个人的武林:渗透测试常规思路分析(一)

    写在前面 渗透测试是门技术,也是一门艺术. 这门技术(艺术)一开始也不是每个人都会的,正所谓没有人一出生就会走路,从不懂到入门到深谙,一步步慢慢来,每个人都是这样:但是在这个过程中,思路无疑是最重要的 ...

  5. 今日头条广告如何优化?这四个思路至关重要

    今日头条广告如何优化?随着互联网的高速发展,在网络平台上投放广告已然成为潮流,而今日头条作为受到大众喜爱的平台之一,有许多广告主想要在今日头条平台内投放广告,但如何优化今日头条广告仍是许多广告主烦恼的 ...

  6. 提高网络服务器性能,优化网络的七条思路 帮您更快提高网络速度

    如何最大限度地提升网络的速度与性能,一直是企业网络管理者们所关注的问题.本文将围绕如何进一步提升网络的速度与性能这一问题,给出业内资深人士和网络专家的七条建议. 使用巨型数据包 使用巨型数据包技术可使 ...

  7. 浅谈Android模块化设计(常规思路)

    移动开发从iPhone手机问世之后,也快有十个年头了,随着App功能的不断的变多,代码规模越来越大,也为了适应多项目组协同开发的工程需要,各种移动端的模块化方案应运而生. 这两年来,各大公司以及各路大 ...

  8. Oracle数据库性能问题分析的一种常规思路

    点击上方"数据和云" 关注我们! 这两天微信群里在讨论一个Oracle数据库性能问题引起业务问题的案例,一位朋友把分析报告发到了群里.正好有空就看了看,感觉这份报告颇有Oracle ...

  9. mysql按工作日查询统计优化_工作日计算问题思路和实现

    项目中目前已有一周表存储了一年中所有的假日,给定查询起始日期和结束日期,推导出查询时间段内工作日是多少.为了简化这个问题,需要下面几个假设. 1. 不考虑周六周日,将其视作普通工作日 2. 假日没有交 ...

最新文章

  1. VC开发Windows客户端软件之旅——前言
  2. 二分图的最大匹配(匈牙利算法)HDU1083
  3. SpringBoot处理JSON数据
  4. centos内核编译与其签名机制
  5. 三心二意,助你好运?
  6. java uuid静态方法_Java UUID compareTo()方法与示例
  7. 【转载】define与typedef区别与联系
  8. CSDN公众号新功能上线,居然还能搜出小姐姐???(文末有福利)
  9. ros构建机器人运动学模型_ROS入门学习之八机器人综合应用
  10. 超好看的引导购买页源码
  11. 在IDEA中设置Java的堆大小
  12. 浏览器怪异模式和标准模式之间的区别 DTD
  13. linux下的C语言编程(总结篇)
  14. 索引sql server_SQL Server索引–系列介绍
  15. iOS开发——源代码管理——git(分布式版本控制和集中式版本控制对比,git和SVN对比,git常用指令,搭建GitHub远程仓库,搭建oschina远程仓库 )...
  16. 书籍折页是什么效果_书籍折页什么样 - 卡饭网
  17. APM编译example
  18. 港股相关交易规则与业务知识
  19. R语言ggplot2 | 如何自定义facet分面的坐标轴范围
  20. 使用DownloadManager进行更新下载,部分机型下载失败解决方案

热门文章

  1. Java中的ClassLoader和SPI机制
  2. form表单的reset
  3. 分布式计算开源框架Hadoop入门实践
  4. short_open_tag 必须打开
  5. XML与DataSet的相互转换类
  6. 自动创建阿里云抢占式实例
  7. Linux环境编译安装OpenJDK
  8. Ubuntu14.04下配置OpenGL及测试代码
  9. 计算机管理员身份有哪些优点,重装系统有什么好处?有哪些理由值得让电脑重装系统?...
  10. 语言趣味编程100例无水印_趣味c语言编程100例(三)