.Net中的并行编程-6.常用优化策略
本文是.Net中的并行编程第六篇,今天就介绍一些我在实际项目中的一些常用优化策略。
一、避免线程之间共享数据
避免线程之间共享数据主要是因为锁的问题,无论什么粒度的锁,最好的线程之间同步方式就是不加锁,这个地方主要措施就是找出数据之间的哪个地方需要共享数据和不需要共享数据的地方,再设计上避免多线程之间共享数据。
在以前做过的某项目,开始时设计的方案:
开始设计时所有的数据都放入到了公共队列,然后队列通知多个线程去处理数据,队列采用互斥锁保证线程同步,造成的结果就是线程进行频繁的上下切换,CPU时间都浪费在了上下文切换上从而导致队列拥堵无法及时处理数据,最终程序因无法处理数据而内存溢出。
一开始解决这个问题是想到了采用更细粒度的锁如原子操作,但使用原子操作又需要回退机制保证活锁问题还要防止浪费CPU的时间等等一系列的问题。。,如果开发完成其实就相当于自己实现了一个如lock之类的互斥锁。所以重新整理了业务需求,改良后的设计如下:
在数据输入进来以后采用一个单独的数据转发器分发到不同的队列,这样就避免了线程之间的竞争,数据转发器其实就相当于我们开发网站时用到了负载均衡器,而且可以根据队列里面的数据不同选择不用的队列或者可以结合CPU,内存使用率进行动态调度。当然改良后的设计满足了性能需求。
所以在进行多线程开发时,尽量避免使用锁,对于必须使用锁的情景要选择合适的锁,对于选择什么类型的锁,我的原则是:能满足性能要求就好,不要刻意追求细粒度的锁。粗粒度的锁性能低但易于使用和理解,细粒度的锁性能高但难以使用和理解,关于操作系统的锁的介绍可参考《windows核心编程》线程同步的章节,在.net平台下也可参考《CLR VIA C#》线程相关章节介绍。
二、注意CPU高速缓存失效,避免频繁的上下文切换。
开发多核程序时高速缓存往往是提高性能的关键,这里的缓存指的是CPU的缓存(L1,L2,L3)。缓存运用得当往往能提高2倍以上的性能。
1.造成CPU缓存失效的原因有:
(1)频繁的修改内存中的数据
(2)使用了原子操作,lock锁等同步方式。
(3)线程上下文的切换。
(4)伪共享造成频繁的刷新高速缓存。
2. 关于频繁的上下文切换造成的原因有:
(1)程序本身的线程都在抢夺CPU资源,也就是CPU无法调度其他的线程,
(2)很多线程都在等待获取互斥锁但是只有一个线程能获取,其他线程不断在唤醒和睡眠之间切换。
3.以上问题的解决方案(只供参考,项目不同方案不同):
(1)避免使用任何形式的锁。
(2)在满足性能的前提下,用最少的线程做最少的事。
(3)再设计上避免修改数据,如以前开发的实时计算的程序,所有的数据只允许读取不允许修改,需要修改则创建一条新数据来代替,类似于Erlang程序的开发方式。
具体有关高速缓存基础内容可以参考《深入理解计算机操作系统》第六章的内容。
三、线程池的的使用场景和注意点:
(1)对于执行时间较短的任务都应当交给线程池去处理而不是开启一个新线程,对于需要长时间处理的任务交给单独的线程去处理。
(2)对于读写文件的任务不要交给线程池处理,因为线程池内的线程属于后台线程,应用程序意外关闭后线程也关闭从而丢失数据。
(3)永远不要自己开发线程池,真正能用到产品级别线程池需要几个月的时间而且需要大量的测试,否则遇到问题悔之晚矣。
四、关于NUMA架构机器的优化。
(1)现代服务器基本都是NUMA架构,在这些机器上我们编写程序时最好开启.net的服务端垃圾回收模式,这样我们分配对象时就能在最近使用CPU对应的内存上去分配。
(2)不要在.net程序中使用绑定线程到指定内核或提升线程优先级的做法,因为如果绑定的线程正好与垃圾回收线程进行竞争那么性能会更慢。
五、选择合适的编程模型
编写并行程序都有固定的编程模型,基本上其他模型都是这几种模型的自由组合,常见的编程模型:
(1)数据并行
(2)任务并行
(3)流水线并行
六、去队列里拉数据还是队列主动推送数据?
一般我们写多线程的程序会将数据先放到队列中,然后函数立即返回,后续再有其他的线程进行处理以达到快速响应客户端的目的,这就涉及到队列主动发送信号通知线程处理还是线程定时去队列里拉取数据,如果采用推送的方式可能造成状态丢失最终有些数据得不到处理而一直待在队列中,如果采用拉取的方式线程的睡眠时间不好把握,睡多了数据处理速度慢,睡少了又浪费CPU,所以我一般采用两者结合的方式,具体参考我的第四篇文章《.Net中的并行编程-4.实现高性能异步队列》
七、异步IO还是同步IO?
异步IO可以解决同步IO的线程阻塞问题(这里的IO分两种:磁盘和网络),基本上所有的web服务器都采用的异步的网络IO,但是对于磁盘最好不要使用异步的磁盘IO,除非在具有SSD的机器上。因为对磁盘异步的读写会造成磁盘存储数据时的碎片化,本来可以顺序写的操作最终可能变成随机写。
结束语:
本文设计的内容只是并行程序优化很少一部分,更多内容还需要我们在实践中不断积累。
本来想写的内容是”.net并行“,结果写完才发现和.net没有关系,当然,这些基础知识和语言没什么太大关系。
本文设计的内容只是建议,我们在编写程序时不要具有教条主义,合理的才是最好的,某些原则不是适合所有情况,我们所做的是不断探索适应变化以达到提升程序性能的目的。
.Net中的并行编程-6.常用优化策略的更多相关文章
- .Net中的并行编程-1.路线图(转)
大神,大神,膜拜膜拜,原文地址:http://www.cnblogs.com/zw369/p/3834559.html 目录 .Net中的并行编程-1.路线图 分析.Net里线程同步机制 .Net中的 ...
- .Net中的并行编程-2.ConcurrentStack的实现与分析
在上篇文章<.net中的并行编程-1.基础知识>中列出了在.net进行多核或并行编程中需要的基础知识,今天就来分析在基础知识树中一个比较简单常用的并发数据结构--.net类库中无锁栈的实现 ...
- .Net中的并行编程-3.ConcurrentQueue实现与分析
在上文<.Net中的并行编程-2.ConcurrentQueue的实现与分析> 中解释了无锁的相关概念,无独有偶BCL提供的ConcurrentQueue也是基于原子操作实现, 由于Con ...
- .Net中的并行编程-5.流水线模型实战
自己在Excel整理了很多想写的话题,但苦于最近比较忙(其实这是借口).... 上篇文章<.Net中的并行编程-4.实现高性能异步队列>介绍了异步队列的实现,本篇文章介绍我实际工作者遇到了 ...
- .Net中的并行编程-4.实现高性能异步队列
上文<.Net中的并行编程-3.ConcurrentQueue实现与分析>分析了ConcurrentQueue的实现,本章就基于ConcurrentQueue实现一个高性能的异步队列,该队 ...
- Python中的并行编程速度
这里主要想记录下今天碰到的一个小知识点:Python中的并行编程速率如何? 我想把AutoTool做一个并行化改造,主要目的当然是想提高多任务的执行速度.第一反应就是想到用多线程执行不同模块任务,但是 ...
- .Net中的并行编程-1.路线图
最近半年一直研究用.net进行并行程序的开发与设计,再研究的过程中颇有收获,所以画了一个图总结了一下并行编程的基础知识点,这些知识点是并行编程的基础,有助于我们编程高性能的程序,里面的某些结构实现机制 ...
- PHP中的数据库一、MySQL优化策略综述
前些天看到一篇文章说到PHP的瓶颈很多情况下不在PHP自身,而在于数据库.我们都知道,PHP开发中,数据的增删改查是核心.为了提升PHP的运行效率,程序员不光需要写出逻辑清晰,效率很高的代码,还要能对 ...
- .NET Framework 4 中的并行编程9---线程安全集合类
原文转载自:http://www.cnblogs.com/xray2005/archive/2011/10/11/2206745.html 在.Net 4中,新增System.Collections. ...
随机推荐
- 学习Data Science/Deep Learning的一些材料
原文发布于我的微信公众号: GeekArtT. 从CFA到如今的Data Science/Deep Learning的学习已经有一年的时间了.期间经历了自我的兴趣.擅长事务的探索和试验,有放弃了的项目 ...
- springboot hessian
注意把hessian的依赖换成4.0.38或者把git文件里的4.0.37放到maven私服中去,推荐使用4.0.37版本.38版本存在序列化bigdecimal的问题. <dependency ...
- Java 7 中的Switch 谈 Java版本更新和反编译知识
Java 7 中的Switch 谈 Java版本更新和反编译知识 学习编程,享受生活,大家好,我是追寻梦的飞飞.今天主要讲述的是Java7中的更新Switch实现内部原理和JAD反编 ...
- 那些年我们写过的T-SQL(上篇)
在当今这个多种不同数据库混用,各种不同语言不同框架融合的年代(一切为了降低成本并高效的提供服务),知识点多如牛毛.虽然大部分SQL脚本可以使用标准SQL来写,但在实际中,效率就是一切,因而每种不同厂商 ...
- HTML5语义标签的实践
<article> 定义一篇文章 论坛发帖 博客文章 一篇文章 <article> <h1>标题</h1> <p>内容</p> ...
- 【WP 8.1开发】推送通知测试服务端程序
所谓推送通知,用老爷爷都能听懂的话说,就是: 1.我的服务器将通知内容发送到微软的通知服务器,再由通知服务器帮我转发消息. 2.那么,微软的推送服务器是如何知道我的服务器要发消息给哪台手机呢?手机客户 ...
- Gephi可视化(二)——Gephi Toolkit叫板Prefuse
继在园子里写的<Gephi可视化(一)——使用Gephi Toolkit创建Gephi应用>介绍了如何使用Gephi Toolkit工具集进行可视化编程后,本篇对Gephi Toolkit ...
- Simptip – 使用 Sass 制作的 CSS Tooltip 效果
Simptip 是一个简单基于 Sass 的 CSS 工具提示效果.帮助你在网站中加入在不同的方向(上.左.右.下)的工具提示,也可以设置不同的颜色如成功.信息.警告和危险.最后还有其他特性如软边.半 ...
- 深度学习中的Data Augmentation方法(转)基于keras
在深度学习中,当数据量不够大时候,常常采用下面4中方法: 1. 人工增加训练集的大小. 通过平移, 翻转, 加噪声等方法从已有数据中创造出一批"新"的数据.也就是Data Augm ...
- C# Socket系列一 简单的创建socket的监听
socket的应用场景,在快速,稳定,保持长连接的数据传输代码.Http也是socket封装出来的,基于一次请求一次回复,然后断开的socket连接封装. 比如我们常见的游戏服务器,目前的很火的物联网 ...