• .net性能调优记录-转自顾式传说


    公司里新上了一个项目,在做性能测试的时候发现一个奇怪的问题,跑同一个流程,在一个48核(HP580 G7 PC server)的服务器上耗时120秒,而在一个4核心的PC机上只要90秒,带着这样的疑问,公司请了微软的相关工程师来解决此问题。

    经过一天的跟踪调试和优化,把耗时降至70几秒,这其中过程包含几个.net对象的优化,确实效果很明显。此文是阶段性结论的一个笔记,也蛮具有指导意义。

    一、DataView.ToTable()后的性能问题

    工程师在跟踪代码的时候发现处理这个方法的时候很慢,占居了整个逻辑代码的大部分时间。优化这个方法后效果很明显。

    查了MSDN,官方并没有给出DataView.ToTable()方法关于性能方面的提示,但是要MSDN看这个方法时,发现老外在06年的时候已经在下面回了一段代码,通过三个方式执行这个方法,发现效率上差异很大。 (MSDN:DataView.ToTable())。

    我复制代码,创建了一个新的工程,确实可以重现问题。整个过程大概如下:

    背景是有一个有500000条数据的DataTable,然后把这个DataTable中的数据赋给DataView,然后从这个DataView通过ToTable()方法,把数据转给另外一个同架构的DataTable。

    第一种方式 创建目标DataTable对象,直接通过toTable()方法转换。过程耗时:27.0504秒。

    第二种方式 创建目标DaTaTable后,对其设置PrimaryKey。然后通过下面代码向目标表添加数据。

                     foreach (DataRow dr in ds.Tables[0].Rows)

                    {

                        DataRow[] drrepetido = dsRes.Tables[0].Select("valor=" + dr["Valor"]);

                        if (drrepetido.Length == 0)

                            dsRes.Tables[0].ImportRow(dr);

                    }

    过程耗时:11.7624秒。

    第三种方式 不根据原架构创建目标DataTable,全新实例化DataTable对象,然后向其添加对应列,然后创建哈希表,循环写入目标表,代码如下:

                    DataTable dt = new DataTable();

                    dt.Columns.Add("valor", ds.Tables[0].Columns["valor"].DataType);

                    Hashtable ht = new Hashtable();

                    foreach (DataRow dr in ds.Tables[0].Rows)

                    {

                        if (!ht.ContainsKey(dr[0]))

                        {

                            ht.Add(dr[0], null);

                            DataRow newRow = dt.NewRow();

                            newRow[0] = dr[0];

                            dt.Rows.Add(newRow);

                        }

                    }

    过程耗时:0.2184秒。

    三种方式对比,发现非常恐怖。但是微软好像还没有给出原因。

    二、StringBuilder()使用不档带来的性能问题

    关于StringBuilder之前也看过很多文章,这次开发商程序中的问题和以前的类似,实例化时没有设置一个比较推荐的长度值,导致在循环体内不断appand()后,StringBuilder对象不断被GC处理。从而消耗了很多时间。

    关于StringBuilder()对象,还是再多加几句吧。其默认维护的Capacity值是16。

    因为StringBuilder对象的创建代价较大,在字符串连接目标较少的情况下,过度滥用StringBuilder会导致性能的浪费而非节约。只有大量的或者无法预知次数的字符串操作,才考虑以StringBuilder来实现。  String类型的“+”连接操作,实际上是重载操作符“+”调用String.Concat来操作,而编译器则会优化这种连接操作的处理,编译器根据其传入参数的个数,一次性分配相应的内存,并依次拷入相应的字符串。 StringBuilder在使用上,最好指定合适的容量值,否则由于默认容量不足而频繁的进行内存分配操作,是不妥的实现方法。  通常情况下,进行简单字符串连接时,应该优先考虑使用String.Concat和String.Join等操作来完成字符串的连接,但是应该留意String.Concat可能存在的装箱操作。

    三、拆装箱带来性能问题

    如果用StringBuilder.toString().trim()来判断StringBuilder是否有值的情况,可以用StringBuilder.Lenth()来代替。

  • 相关阅读:
    面向连接的网络应用程序--服务器端
    使用完整读写函数的网络应用程序
    套接字编程基础
    网络编程基础
    传输控制协议TCP
    UDP协议
    电子词典
    strtok()函数、fseek()函数、fwrite()函数、fread()函数的使用
    指针与数组
    软件推荐----RDO(Remote Desktop Organizer)
  • 原文地址:https://www.cnblogs.com/mlwork/p/11752745.html
Copyright © 2020-2023  润新知