本文是.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.常用优化策略的更多相关文章

  1. .Net中的并行编程-1.路线图(转)

    大神,大神,膜拜膜拜,原文地址:http://www.cnblogs.com/zw369/p/3834559.html 目录 .Net中的并行编程-1.路线图 分析.Net里线程同步机制 .Net中的 ...

  2. .Net中的并行编程-2.ConcurrentStack的实现与分析

    在上篇文章<.net中的并行编程-1.基础知识>中列出了在.net进行多核或并行编程中需要的基础知识,今天就来分析在基础知识树中一个比较简单常用的并发数据结构--.net类库中无锁栈的实现 ...

  3. .Net中的并行编程-3.ConcurrentQueue实现与分析

    在上文<.Net中的并行编程-2.ConcurrentQueue的实现与分析> 中解释了无锁的相关概念,无独有偶BCL提供的ConcurrentQueue也是基于原子操作实现, 由于Con ...

  4. .Net中的并行编程-5.流水线模型实战

    自己在Excel整理了很多想写的话题,但苦于最近比较忙(其实这是借口).... 上篇文章<.Net中的并行编程-4.实现高性能异步队列>介绍了异步队列的实现,本篇文章介绍我实际工作者遇到了 ...

  5. .Net中的并行编程-4.实现高性能异步队列

    上文<.Net中的并行编程-3.ConcurrentQueue实现与分析>分析了ConcurrentQueue的实现,本章就基于ConcurrentQueue实现一个高性能的异步队列,该队 ...

  6. Python中的并行编程速度

    这里主要想记录下今天碰到的一个小知识点:Python中的并行编程速率如何? 我想把AutoTool做一个并行化改造,主要目的当然是想提高多任务的执行速度.第一反应就是想到用多线程执行不同模块任务,但是 ...

  7. .Net中的并行编程-1.路线图

    最近半年一直研究用.net进行并行程序的开发与设计,再研究的过程中颇有收获,所以画了一个图总结了一下并行编程的基础知识点,这些知识点是并行编程的基础,有助于我们编程高性能的程序,里面的某些结构实现机制 ...

  8. PHP中的数据库一、MySQL优化策略综述

    前些天看到一篇文章说到PHP的瓶颈很多情况下不在PHP自身,而在于数据库.我们都知道,PHP开发中,数据的增删改查是核心.为了提升PHP的运行效率,程序员不光需要写出逻辑清晰,效率很高的代码,还要能对 ...

  9. .NET Framework 4 中的并行编程9---线程安全集合类

    原文转载自:http://www.cnblogs.com/xray2005/archive/2011/10/11/2206745.html 在.Net 4中,新增System.Collections. ...

随机推荐

  1. scrollview 中嵌套多个listview的最好解决办法

    在scrollview中嵌套多个listview的显示问题. 只需要调用如下的方法传入listview和adapter数据即可. /** * 动态设置ListView组建的高度 */ public s ...

  2. 前端学PHP之基础语法

    × 目录 [1]代码标识 [2]注释 [3]输出 [4]计算表达式 [5]大小写 [6]空白符 前面的话 PHP是一种创建动态交互性站点的强有力的服务器端脚本语言.PHP能够包含文本.HTML.CSS ...

  3. 《BI那点儿事》数据挖掘各类算法——准确性验证

    准确性验证示例1:——基于三国志11数据库 数据准备: 挖掘模型:依次为:Naive Bayes 算法.聚类分析算法.决策树算法.神经网络算法.逻辑回归算法.关联算法提升图: 依次排名为: 1. 神经 ...

  4. Tools - Markdown

    Markdown 轻量级标记语言,使用易读易写的纯文本格式和类似HTML的标记语法来编写具有一定的格式的文档. wiki - Markdown 三分钟学会书写格式良好的笔记(Markdown) 为知笔 ...

  5. [python]进阶学习之阅读代码

    起因 最近在公司的任务是写一些简单的运营工具,因为是很小的工具,所以就用了github上面的一个开源项目flask-admin,可以省去很多的事情. 但是,这个开源项目是个人维护的项目,所以文档相对简 ...

  6. SQLServer学习笔记系列7

    一.写在前面的话 转眼又是周一,回想双休的日子,短暂而幸福,在阳光明媚的下午,可以自己做自己想做的任何事,惬意舒适,或读书,或运动,或音乐,当我们静下心来慢慢感受这些的时候,会突然发觉,原来生活是这么 ...

  7. oracle创建表相关

    --创建表 create table person( id number primary key, name ), birth date ); --创建序列 create sequence perso ...

  8. 第23/24周 临时数据库(TempDb)

    在今天的性能调优培训里我们讨论下TempDb——SQL Server的公共厕所,在SQL Server里我是这样描述它的.我们的每个人都会经常使用TempDb.有些人直接使用它,有些人不直接使用它.今 ...

  9. SQL Server代理(10/12):使用代理账号运行作业

    SQL Server代理是所有实时数据库的核心.代理有很多不明显的用法,因此系统的知识,对于开发人员还是DBA都是有用的.这系列文章会通俗介绍它的很多用法. 在这一系列的上一篇,你查看了msdb库下用 ...

  10. HTML5实现3D和2D可视化QuadTree四叉树碰撞检测

    QuadTree四叉树顾名思义就是树状的数据结构,其每个节点有四个孩子节点,可将二维平面递归分割子区域.QuadTree常用于空间数据库索引,3D的椎体可见区域裁剪,甚至图片分析处理,我们今天介绍的是 ...