• 部分转载[C#性能优化实践]


    全文出处:http://www.infoq.com/cn/articles/C-sharp-performance-optimization

    1.性能

       主要指两个方面:内存消耗和执行速度。性能优化简而言之,就是在不影响系统运行正确性的前提下,使之运行地更快,完成特定功能所需的时间更短。

    2.理解瓶颈

       99%的性能消耗是由于1%的代码造成的。大部分性能优化都是针对这1%的瓶颈代码进行的。具体实施也就分为两步:“发现瓶颈”和“消除瓶颈”。

    3.切忌过度

       性能优化本身是有成本的。这个成本不单单体现在做性能优化所付出的工作量,还包括为性能优化而写出复杂的代码导致额外的维护成本,比如引入新的Bug,额外的内存开销等。性能优化常常需要在收益和成本之间做出权衡。

    4.如何发现性能瓶颈

       性能优化的第一步是发现性能瓶颈,下面是一些定位性能瓶颈的实践。

       A.如何获取内存消耗

          以下代码可以获取某个操作的内存消耗:

    long start = GC.GetTotalMemory(true);
    // 在这里写需要被测试内存消耗的代码,例如,创建一个GcMultiRow
    var gcMulitRow1 = new GcMultiRow();
    GC.Collect();
    // 确保所有内存都被GC回收
    GC.WaitForFullGCComplete();
    long end = GC.GetTotalMemory(true);
    long useMemory = end - start; 

        B.如何获取时间消耗

           以下代码可以获取某个操作时间消耗:

    System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
    watch.Start();
    for (int i = 0; i < 1000; i++)
    {
        gcMultiRow1.Sort();
    }
    watch.Stop();
    var useTime = (double)watch.ElapsedMilliseconds / 1000;

         ----为了获得更加稳定的时间消耗,这里把一个操作循环执行了1000次,取时间消耗的平均值以排除不稳定数据。

    5.性能优化的方法和技巧

      A.优化程序结构

      B.缓存

        缓存(Cache)是性能优化中最常用的手段,针对需要频繁的获取一些数据,同时每次获取数据需要的时间比较长的场景。如果使用了缓存的优化方法,需要特别注意缓存数据的同步:如果真实的数据发生了变化,应该及时的清除缓存数据,确保不会因为缓存而使用了错误的数据。使用缓存的情况比较多, 最简单的情况就是缓存到一个Field或临时变量里。

    forint i = 0; i < gcMultiRow.RowCount; i++)
    { 
    // Do something; 
    } 

        以上代码一般情况下是没有问题的,但是,如果GcMultiRow的行数比较大。而RowCount属性的取值又比较慢的时候,就需要使用缓存来做性能优化。

    int rowCount = gcMultiRow.RowCount;
    for (int i = 0; i < rowCount; i++)
    {
    // Do something;
    }

       C.延迟加载

          大多时候,对于创建需要花费较长时间的对象,往往并不是所有的场景下都需要使用。这时,使用懒构造的方法可以有效提高程序启动性能。

          举例来说,对象A需要内部创建对象B。对象B的构造时间比较长。 一般做法:

    public class A
    {
        public B _b = new B();
    }

          一般做法下,由于构造对象A的同时要构造对象B,导致A的构造速度也变慢了。

          优化做法:

    public class A
    {
        private B _b;
        public B BProperty
        {
            get
            {
                if(_b == null)
                {
                    _b = new B();
                }
                return _b;
            }
        }
    }

          优化后,构造A的时候就不需要创建B对象,有效的提高了A的构造性能。

      D.优化算法

      E.正确的使用既有数据结构

         .NET平台有很多现成的数据结构。我们应该了解这些数据结构,提升我们程序的性能。

        例如:

                1. String的加运算符和StringBuilder:

                    字符串的操作是我们经常遇到的基本操作之一。 我们经常会写这样的代码 string str = str1 + str2。当操作的字符串很少的时候,这样的操作没有问题。但是如果大量操作的时候(例如文本文件的Save/Load, Asp.net的Render),这样做就会带来严重的性能问题。这时,我们就应该用StringBuilder来代替string的加操作。

               2. Dictionary 和 List:

                   Dictionary和List是最常用的两种集合类。选择正确的集合类可以很大的提升程序的性能。为了做出正确的选择,我们应该对Dictionary 和List的各种操作的性能比较了解。 下表中粗略的列出了两种数据结构的性能比较。

    操作                   List         Dictionary
    
    索引                   快            慢
    
    Find(Contains)       慢            快
    
    Add                   快            慢
    
    Insert                慢            快
    
    Remove                慢            快

                 3.TryGetValue: 对于Dictionary的取值,比较直接的方法是如下代码:

    if(_dic.ContainKey("Key")
    {
        return _dic["Key"];
    }      

                  当需要大量取值的时候,这样的取法会带来性能问题。优化方法如下

    object value;
    if(_dic.TryGetValue("Key", out value))
    {
    return value;
    }

                 后一种用法要比前一种用法取值性能提高一倍。

                 4. 为Dictionary选择合适的Key:

                     Dictionary的取值性能很大情况下取决于做Key的对象的Equals和GetHashCode两个方法的性能。如果可以的话,使用Int做Key性能最好。如果是一个自定义的Class做Key的话,最好保证以下两点:

                    1)不同对象的GetHashCode重复率低。

                    2)GetHashCode和Equals方法简单,效率高。

                 5. List的Sort和BinarySearch性能很好,如果能满足功能需求,推荐直接使用。

    List<int> list = new List<int>{3, 10, 15};
    
     
    
    list.BinarySearch(10); // 对于存在的值,结果是1
    
     
    
    list.BinarySearch(8); // 对于不存在的值,会使用负数表示位置,
    
     
    
    // 如查找8时,结果是-2, 查找0结果是-1,查找100结果是-4.
  • 相关阅读:
    2020 CCPC-Wannafly Winter Camp Day6 ---I. 变大!
    Codeforces 1295F Good Contest
    2020 CCPC-Wannafly Winter Camp Day6 ---A. Convolution
    centos下kubernetes+flannel部署(旧)
    无网络centos7中部署kubernetes
    利用Openvswitch实现不同物理机中的Docker容器互连
    docker-py的配置与使用
    通过Docker配置DNS服务器
    在 OS X Yosemite 中部署Mesos
    Docker初识
  • 原文地址:https://www.cnblogs.com/notebook2011/p/3181449.html
Copyright © 2020-2023  润新知