ImageVerifierCode 换一换
格式:DOCX , 页数:34 ,大小:38.53KB ,
资源ID:5514601      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5514601.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(NET 性能优化方法总结.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

NET 性能优化方法总结.docx

1、NET 性能优化方法总结.NET 性能优化方法总结 Ver 1.0 2009-1-20目录1. C#语言方面. 41.1 垃圾回收. 41.1.1 避免不必要的对象创建. 41.1.2 不要使用空析构函数 . 41.1.3 实现 IDisposable 接口. 41.2 String 操作. 51.2.1 使用 StringBuilder 做字符串连接. 51.2.2 避免不必要的调用 ToUpper 或 ToLower 方法. 51.2.3 最快的空串比较方法. 61.3 多线程. 61.3.1 线程同步. 61.3.2 使用 ThreadStatic 替代 NameDataSlot . 7

2、1.3.3 多线程编程技巧. 71.4 类型系统. 81.4.1 避免无意义的变量初始化动作. 81.4.2 ValueType 和 ReferenceType. 81.4.3 尽可能使用最合适的类型. 91.5 异常处理. 101.5.1 不要吃掉异常. 101.5.2 不要吃掉异常信息. 101.5.3 避免不必要的抛出异常. 101.5.4 避免不必要的重新抛出异常. 101.5.5 捕获指定的异常,不要使用通用的System.Exception. 101.5.6 要在finally里释放占用的资源. 111.6 反射. 111.6.1 反射分类. 121.6.2 动态创建对象. 121

3、.6.3 动态方法调用. 121.6.4 推荐的使用原则. 121.7 基本代码技巧. 131.7.1 循环写法. 131.7.2 拼装字符串. 131.7.3 避免两次检索集合元素. 131.7.4 避免两次类型转换. 141.7.5为字符串容器声明常量,不要直接把字符封装在双引号 里面。. 141.7.6 用StringBuilder代替使用字符串连接符 “+”. 141.7.7 避免在循环体里声明变量,. 151.8 Hashtable. 151.8.1 Hashtable机理. 151.8.2 使用HashTale代替其他字典集合类型的情形:. 161.9 避免使用ArrayList。

4、. 161.10从XML对象读取数据. 171.11 避免使用递归调用和嵌套循环,. 171.12 使用适当的Caching策略来提高性能. 172. Ado.Net 172.1 应用A的一些思考原则. 182.2 Connection. 182.2.1 在方法中打开和关闭连接. 182.2.2 显式关闭连接. 182.2.3 确保连接池启用. 192.2.4 不要缓存连接. 192.3 Command. 192.3.1 使用ExecuteScalar和ExecuteNonQuery. 192.3.2 使用Prepare. 192.3.3 使用绑定变量 . 192.4 DataReader 2

5、02.4.1 显式关闭DataReader 202.4.2 用索引号访问代替名称索引号访问属性. 202.4.3 使用类型化方法访问属性. 202.4.4 使用多数据集. 202.5 DataSet 212.5.1 利用索引加快查找行的效率. 212. 使用DataView. 213.ASP.NET. 213.1 减少往返行程(Reduce Round Trips). 213.2 避免阻塞和长时间的作业. 223.3 使用缓存. 223.4 多线程. 223.5 系统资源. 233.6 页面处理. 233.7 ViewState. 234.JScript 244.1 JScript性能优化的基

6、本原则. 244.2 JScript语言本身的优化. 244.3 DOM相关. 274.4 其他. 28 1. C#语言方面 1.1 垃圾回收垃圾回收解放了手工管理对象的工作,提高了程序的健壮性,但副作用就是程序代码可能对于对象创建变得随意。1.1.1 避免不必要的对象创建由于垃圾回收的代价较高,所以C#程序开发要遵循的一个基本原则就是避免不必要的对象创建。以下列举一些常见的情形。1.1.1.1 避免循环创建对象 如果对象并不会随每次循环而改变状态,那么在循环中反复创建对象将带来性能损耗。高效的做法是将对象提到循环外面创建。1.1.1.2 在需要逻辑分支中创建对象如果对象只在某些逻辑分支中才被

7、用到,那么应只在该逻辑分支中创建对象。1.1.1.3 使用常量避免创建对象程序中不应出现如 new Decimal(0) 之类的代码,这会导致小对象频繁创建及回收,正确的做法是使用Decimal.Zero常量。我们有设计自己的类时,也可以学习这个设计手法,应用到类似的场景中。1.1.1.4 使用StringBuilder做字符串连接 1.1.2 不要使用空析构函数 如果类包含析构函数,由创建对象时会在 Finalize 队列中添加对象的引用,以保证当对象无法可达时,仍然可以调用到 Finalize 方法。垃圾回收器在运行期间,会启动一个低优先级的线程处理该队列。相比之下,没有析构函数的对象就没

8、有这些消耗。如果析构函数为空,这个消耗就毫无意义,只会导致性能降低!因此,不要使用空的析构函数。在实际情况中,许多曾在析构函数中包含处理代码,但后来因为种种原因被注释掉或者删除掉了,只留下一个空壳,此时应注意把析构函数本身注释掉或删除掉。1.1.3 实现 IDisposable 接口垃圾回收事实上只支持托管内在的回收,对于其他的非托管资源,例如 Window GDI 句柄或数据库连接,在析构函数中释放这些资源有很大问题。原因是垃圾回收依赖于内在紧张的情况,虽然数据库连接可能已濒临耗尽,但如果内存还很充足的话,垃圾回收是不会运行的。C#的 IDisposable 接口是一种显式释放资源的机制。通

9、过提供 using 语句,还简化了使用方式(编译器自动生成 try . finally 块,并在 finally 块中调用 Dispose 方法)。对于申请非托管资源对象,应为其实现 IDisposable 接口,以保证资源一旦超出 using 语句范围,即得到及时释放。这对于构造健壮且性能优良的程序非常有意义!为防止对象的 Dispose 方法不被调用的情况发生,一般还要提供析构函数,两者调用一个处理资源释放的公共方法。同时,Dispose 方法应调用 System.GC.SuppressFinalize(this),告诉垃圾回收器无需再处理 Finalize 方法了。 1.2 String

10、 操作1.2.1 使用 StringBuilder 做字符串连接String 是不变类,使用 + 操作连接字符串将会导致创建一个新的字符串。如果字符串连接次数不是固定的,例如在一个循环中,则应该使用 StringBuilder 类来做字符串连接工作。因为 StringBuilder 内部有一个 StringBuffer ,连接操作不会每次分配新的字符串空间。只有当连接后的字符串超出 Buffer 大小时,才会申请新的 Buffer 空间。典型代码如下: StringBuilder sb = new StringBuilder( 256 );for ( int i = 0 ; i Results

11、.Count; i + )sb.Append (Resultsi);如果连接次数是固定的并且只有几次,此时应该直接用 + 号连接,保持程序简洁易读。实际上,编译器已经做了优化,会依据加号次数调用不同参数个数的 String.Concat 方法。例如:String str = str1 + str2 + str3 + str4;会被编译为 String.Concat(str1, str2, str3, str4)。该方法内部会计算总的 String 长度,仅分配一次,并不会如通常想象的那样分配三次。作为一个经验值,当字符串连接操作达到 10 次以上时,则应该使用 StringBuilder。 这

12、里有一个细节应注意:StringBuilder 内部 Buffer 的缺省值为 16 ,这个值实在太小。按 StringBuilder 的使用场景,Buffer 肯定得重新分配。经验值一般用 256 作为 Buffer 的初值。当然,如果能计算出最终生成字符串长度的话,则应该按这个值来设定 Buffer 的初值。使用 new StringBuilder(256) 就将 Buffer 的初始长度设为了256。1.2.2 避免不必要的调用 ToUpper 或 ToLower 方法String是不变类,调用ToUpper或ToLower方法都会导致创建一个新的字符串。如果被频繁调用,将导致频繁创建字

13、符串对象。这违背了前面讲到的“避免频繁创建对象”这一基本原则。例如,bool.Parse方法本身已经是忽略大小写的,调用时不要调用ToLower方法。另一个非常普遍的场景是字符串比较。高效的做法是使用 Compare 方法,这个方法可以做大小写忽略的比较,并且不会创建新字符串。例: const string C_VALUE = COMPARE;if (String.Compare(sVariable, C_VALUE, true) = 0)Console.Write(SAME); 还有一种情况是使用 HashTable 的时候,有时候无法保证传递 key 的大小写是否符合预期,往往会把 key

14、 强制转换到大写或小写方法。实际上 HashTable 有不同的构造形式,完全支持采用忽略大小写的 key: new HashTable(StringComparer.OrdinalIgnoreCase)。1.2.3 最快的空串比较方法将String对象的Length属性与0比较是最快的方法:if (str.Length = 0)其次是与String.Empty常量或空串比较:if (str = String.Empty)或if (str = )注:C#在编译时会将程序集中声明的所有字符串常量放到保留池中(intern pool),相同常量不会重复分配。 1.3 多线程 1.3.1 线程同步线

15、程同步是编写多线程程序需要首先考虑问题。C#为同步提供了 Monitor、Mutex、AutoResetEvent 和 ManualResetEvent 对象来分别包装 Win32 的临界区、互斥对象和事件对象这几种基础的同步机制。C#还提供了一个lock语句,方便使用,编译器会自动生成适当的 Monitor.Enter 和 Monitor.Exit 调用。1.3.1.1 同步粒度同步粒度可以是整个方法,也可以是方法中某一段代码。为方法指定 MethodImplOptions.Synchronized 属性将标记对整个方法同步。例如: MethodImpl(MethodImplOptions.

16、Synchronized)public static SerialManager GetInstance()if (instance = null )instance = new SerialManager(); return instance;通常情况下,应减小同步的范围,使系统获得更好的性能。简单将整个方法标记为同步不是一个好主意,除非能确定方法中的每个代码都需要受同步保护。1.3.1.2 同步策略使用 lock 进行同步,同步对象可以选择 Type、this 或为同步目的专门构造的成员变量。避免锁定Type 锁定Type对象会影响同一进程中所有AppDomain该类型的所有实例,这不仅可

17、能导致严重的性能问题,还可能导致一些无法预期的行为。这是一个很不好的习惯。即便对于一个只包含static方法的类型,也应额外构造一个static的成员变量,让此成员变量作为锁定对象。避免锁定 this锁定 this 会影响该实例的所有方法。假设对象 obj 有 A 和 B 两个方法,其中 A 方法使用 lock(this) 对方法中的某段代码设置同步保护。现在,因为某种原因,B 方法也开始使用 lock(this) 来设置同步保护了,并且可能为了完全不同的目的。这样,A 方法就被干扰了,其行为可能无法预知。所以,作为一种良好的习惯,建议避免使用 lock(this) 这种方式。使用为同步目的专

18、门构造的成员变量这是推荐的做法。方式就是 new 一个 object 对象, 该对象仅仅用于同步目的。如果有多个方法都需要同步,并且有不同的目的,那么就可以为些分别建立几个同步成员变量。 1.3.1.4 集合同步C#为各种集合类型提供了两种方便的同步机制:Synchronized 包装器和 SyncRoot 属性。 / Creates and initializes a new ArrayList ArrayList myAL = new ArrayList();myAL.Add( The );myAL.Add( quick );myAL.Add( brown );myAL.Add( fox

19、); / Creates a synchronized wrapper around the ArrayList ArrayList mySyncdAL = ArrayList.Synchronized(myAL); 调用 Synchronized 方法会返回一个可保证所有操作都是线程安全的相同集合对象。考虑 mySyncdAL0 = mySyncdAL0 + test 这一语句,读和写一共要用到两个锁。一般讲,效率不高。推荐使用 SyncRoot 属性,可以做比较精细的控制。 1.3.2 使用 ThreadStatic 替代 NameDataSlot 存取 NameDataSlot 的 Th

20、read.GetData 和 Thread.SetData 方法需要线程同步,涉及两个锁:一个是 LocalDataStore.SetData 方法需要在 AppDomain 一级加锁,另一个是 ThreadNative.GetDomainLocalStore 方法需要在 Process 一级加锁。如果一些底层的基础服务使用了 NameDataSlot,将导致系统出现严重的伸缩性问题。规避这个问题的方法是使用 ThreadStatic 变量。示例如下: public sealed class InvokeContextThreadStaticprivate static InvokeConte

21、xt current;private Hashtable maps = new Hashtable();1.3.3 多线程编程技巧1.3.3.1 使用 Double Check 技术创建对象 internal IDictionary KeyTableget if ( this ._keyTable = null )lock ( base ._lock)if ( this ._keyTable = null )this ._keyTable = new Hashtable(); return this ._keyTable; 创建单例对象是很常见的一种编程情况。一般在 lock 语句后就会直接创

22、建对象了,但这不够安全。因为在 lock 锁定对象之前,可能已经有多个线程进入到了第一个 if 语句中。如果不加第二个 if 语句,则单例对象会被重复创建,新的实例替代掉旧的实例。如果单例对象中已有数据不允许被破坏或者别的什么原因,则应考虑使用 Double Check 技术。 1.4 类型系统1.4.1 避免无意义的变量初始化动作CLR保证所有对象在访问前已初始化,其做法是将分配的内存清零。因此,不需要将变量重新初始化为0、false或null。需要注意的是:方法中的局部变量不是从堆而是从栈上分配,所以C#不会做清零工作。如果使用了未赋值的局部变量,编译期间即会报警。不要因为有这个印象而对所

23、有类的成员变量也做赋值动作,两者的机理完全不同!1.4.2 ValueType 和 ReferenceType 1.4.2.1 以引用方式传递值类型参数值类型从调用栈分配,引用类型从托管堆分配。当值类型用作方法参数时,默认会进行参数值复制,这抵消了值类型分配效率上的优势。作为一项基本技巧,以引用方式传递值类型参数可以提高性能。1.4.2.2 为 ValueType 提供 Equals 方法.net 默认实现的 ValueType.Equals 方法使用了反射技术,依靠反射来获得所有成员变量值做比较,这个效率极低。如果我们编写的值对象其 Equals 方法要被用到(例如将值对象放到 HashTa

24、ble 中),那么就应该重载 Equals 方法。 public struct Rectanglepublic double Length;public double Breadth;public override bool Equals ( object ob)if (ob is Rectangle)return Equels (Rectangle)ob)else return false ; private bool Equals (Rectangle rect)return this .Length = rect.Length & this .Breadth = rect.Breach;

25、 1.4.2.3 避免装箱和拆箱C#可以在值类型和引用类型之间自动转换,方法是装箱和拆箱。装箱需要从堆上分配对象并拷贝值,有一定性能消耗。如果这一过程发生在循环中或是作为底层方法被频繁调用,则应该警惕累计的效应。一种经常的情形出现在使用集合类型时。例如: ArrayList al = new ArrayList();for ( int i = 0 ; i 1000 ; i + )al.Add(i); / Implicitly boxed because Add() takes an object int f = ( int )al 0 ; / The element is unboxed 但是

26、得当心!如果你像使用引用类型那么频繁的使用一个值类型的话,值类型的优势会很快被耗尽。比如,把一个值类型压到一个含有对象类型的群集。这叫做装箱,很耗用处理器周期,尤其是当你的代码在把它作为值(对它进行数学运算)和把它作为引用之间来回运行时。 1.4.3 尽可能使用最合适的类型 尽可能使用最合适的类型来描述数据,从而减少类型转换。 使用泛型来创建群集和其它的数据结构,这样,在运行时,它们就可以被实例化来存储刚好合适的类型。这节省了装箱/拆箱和类型转换的时间。 在C#中使用as,而不是is。关键字is用来查看引用是否可以被作为某个具体的类型,但是并不返回转换到这个类型的引用。所以,通常当你从is获得

27、一个正的结果时,你首先应该cast有效地执行两次cast。采用as关键词时,如果可用,则返回cast为新类型的引用;否则返回null。你可以查看null然后做你喜欢做的事情。整体来说,As方法要比is方法快50%。1.5 异常处理异常也是现代语言的典型特征。与传统检查错误码的方式相比,异常是强制性的(不依赖于是否忘记了编写检查错误码的代码)、强类型的、并带有丰富的异常信息(例如调用栈)。1.5.1 不要吃掉异常关于异常处理的最重要原则就是:不要吃掉异常。这个问题与性能无关,但对于编写健壮和易于排错的程序非常重要。这个原则换一种说法,就是不要捕获那些你不能处理的异常。吃掉异常是极不好的习惯,因为

28、你消除了解决问题的线索。一旦出现错误,定位问题将非常困难。除了这种完全吃掉异常的方式外,只将异常信息写入日志文件但并不做更多处理的做法也同样不妥。1.5.2 不要吃掉异常信息有些代码虽然抛出了异常,但却把异常信息吃掉了。为异常披露详尽的信息是程序员的职责所在。如果不能在保留原始异常信息含义的前提下附加更丰富和更人性化的内容,那么让原始的异常信息直接展示也要强得多。千万不要吃掉异常。1.5.3 避免不必要的抛出异常抛出异常和捕获异常属于消耗比较大的操作,在可能的情况下,应通过完善程序逻辑避免抛出不必要不必要的异常。与此相关的一个倾向是利用异常来控制处理逻辑。尽管对于极少数的情况,这可能获得更为优

29、雅的解决方案,但通常而言应该避免。1.5.4 避免不必要的重新抛出异常如果是为了包装异常的目的(即加入更多信息后包装成新异常),那么是合理的。但是有不少代码,捕获异常没有做任何处理就再次抛出,这将无谓地增加一次捕获异常和抛出异常的消耗,对性能有伤害。 1.5.5 捕获指定的异常,不要使用通用的System.Exception. /避免try catch(Exception exc)/推荐trycatch(System.NullReferenceException exc) catch(System.ArgumentOutOfRangeException exc) catch(System.InvalidCastException exc) 1.5.6 要在finally里释放占用的资源使用Try.catch.finally时, 要在finally里释放占用的资源如连接,文件流等,不然在Catch到错误后占用的资源不能释放。try.catch.finallyconntion.close() 1.6 反射反射是一项很基础的技术,它将编译期间的静态绑定转换为延迟到运行期间的动态绑定。在很多场景下(特别是类框架的设计),可以获

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1