• C# 程序性能提升篇-2、类型(字段类型、class和struct)的错误定义所影响性能浅析


    前景提要:

      编写程序时,也许你不经意间,就不知不觉的定义了错误的类型,从而发生了额外的性能消耗,从而降低了效率,不要说就发生那么一次两次,如果说是程序中发生了循环、网络程序(不断请求处理的)等这些时候,减少了不必要额外的消耗,使优化程序提高效率的一种途径。不仅跬步,无以至千里,不积小流,无以至江河。优化从点点滴滴做起。

    一、问题抛出:

      大家先看这么一段定义        

      class ReserveData 
      {
        public string ReserveId;  
        public string patient_id;
        public string patient_name; 
        public string queue_type_id;
        public string source_code;
        public string IsCall;  
        public string date;
        public string start_time;
        public string end_time;
        public string reserve_timespan_id;
    }

      这是真实的摘自同事代码,先不说命名规则,Pascal、骆驼命名,(其中我们自己定义来自数据库使用骆驼,自定义变量使用Pascal)

      这段代码主要用途是向前台页面序列化ReserveData的List的json。

      以前我从没感觉类型定义会是什么问题,这个谁会出什么问题呢,可是有人真的就这么干,最后还不以为然。

    二、问题解析一——字段类型定义

      在您这么定义的时候,您觉得可能这样定义并没有什么,甚至会说:“我都工作,两三年了,别对我指手画脚的”。

      一共工作过两家公司,均有一些工作两三年的同事,这样使用。偶的神啊!

      2.1 不同层面分析

        2.1.1 从程序员角度理解  

          从程序员角度,我真的理解不了,你要表达的意思,明明是bool,一个true,false的意思,你变成string,datetime,也定义成string。  我去问他们,来了一句,“那怎么了,又不影响使用,你别纠结这些问题了,想想流程”。我不知该说什么。

        2.1.2 从机器CLR去理解  

          确实,我够智能,你怎么着,我都给你正常编译、执行,但是正常干活已经够累的了,怎么还给我找事,告诉你,消耗cpu,内存过多,我就给你宕机去。

        2.1.3 实际使用中的我

           苦逼的我在前台js接收json时,针对bool怎么也是解析不出来,各种怪现象,看了源代码,有种想抽她的冲动,bool类型返回的是string类型的“True”,int32返回的也变成string类型数值,datetime类型也不是预想中的毫秒值,变成了string(2014/05/30 09:00:00),你说我能不抽她吗??

        2.1.4 性能分析

          现在咱们,就分析一下这段类型定义。

            在这其中 ReserveId 其实是 int32
            IsCall 其实是 bool
            start_time、end_time 其实是 Datetime
            patient_name 是 String 其他的也可能有别的类型,

          这里主要指出的不按真实情况,定义应有的类型,接收应有的数据,而自以为事的胡乱定义。第一、原本是值类型的,如果您定义成了string引用类型,可能造成不必要的装箱,性能损失。(补充一句,谢谢网友“ 冰麟轻武”提醒,这里使用类接收或者承载数据库数据之后,需要对其进行操作的,string 类型的Datetime,需要使用类型装换,同时还有一些其他的操作,“可能”会造成装箱,拆箱。可能使用Convert、(Int)强转、int.Parse()等类似 值类型→引用类型,引用类型→值类型) 第二、原本是引用类型的,如果您定义成了Int32、Boolean等值类型,可能直接就会有语法错误。第三,增加程序员之间的配合难度。以及会是程序中出现各种怪问题。

          装箱是很消耗性能的一种操作,这里不再详述:可参看:C# 程序性能提升篇-1、装箱和拆箱,枚举的ToString浅析

          实际事例:像这种List<ReserveData>,可能会有多条,每次都会进行装箱,就按本例使用示例分析一下性能问题(以实际现状分析,本人从事医疗辅助软件开发)
            (说明一下,一般医院给这种医疗辅助软件的服务器,就那么一台(四核八线程,4G内存),更有可能者,只给你一个虚拟机。web和DB在一台服务器,这还不止一个医疗辅助软件系统,还有其他的多媒体展示,或者其他医院系统)
            示例:某医院有一百个终端屏幕(小医院的点数,大医院会上千),其实就是请求客户端。每个终端屏幕每隔60s请求一次(这一般是最小的),甚至有的医院要求5s刷新,每次列表有10个患者。ok,这是实际情景
              咱们数学计算一下,预定义量,假设每次装箱耗时1ms、内存消耗1k,cpu使用0.001%
                    (以上使用10个字段,8个可能发生装箱,每次list按10个计算)  
              粗略计算一下100个同时请求的即时消耗
                时间 100个屏幕*10个患者*8个装箱字段*1s时间*1ms额外消耗==8000ms =8s
                内存 100个屏幕*10个患者*8个装箱字段*1s时间*1K 额外消耗==8000K  =8M
                CPU  100个屏幕*10个患者*8个装箱字段*1s时间*0.001%额外消耗==8%

              这还仅仅是系统中的一角,如果有更多的这种额外消耗,那么程序就死定了

          综上所述,额外消耗(可能所有的基数并不准确,但是消耗是一定的,你懒了,机器多干活了,必然会有多的消耗(能量守恒定律码)),只不过是微乎其微的消耗;
            桌面程序,请求数少,可以忽略不计;
            局域网程序,像我们这种,频繁多请求,在服务器cpu、内存控制下,就得考虑额外消耗;
            互联网则更需要考虑,轻则上千,重则千万级别,再深了更别说了。这种额外的消耗(完全可以避免的消耗),并不在正常消耗之内的消耗,可能就是造成您的cpu,内存,居高不小的主要原因。

    三、问题解析二——class和struct

      3.1概念简述

          3.1.1 不用多说,class 是引用类型,struct是值类型  

          3.1.2 补充一句,引用类型开辟内存栈指针,内存堆存放数据,具体内存等资源释放由CLR的GC处理,偏重型;   值类型,存放于内存栈中,在作用域结束释放,轻型  

          3.1.3 class与struct差不多一样,struct 是C、C++旧时代的产物,class才是王道,才是面向对象中使用的。C#中之所以有struct 是为了兼容C、C++程序员才过度的产物。估计很多您search过,都是这个答案吧。回忆,看过的教程、百度、google,博客园,甚至曾经的自己,都是这种想法。

        3.2什么时候使用类、什么时候使用struct  

          google一下就很多了,不在深入抄袭,但是看到以上类似3.1.3的话您就别看了,我给您补充一下:

            1.对于轻量级的数据组,类似上面的就是一些字段、属性的序列化,没有进一步抽象,继承的需求可以考虑使用Struct;
            2.struct  类型是一种值类型,通常用来封装小型相关变量组(MSDN:http://msdn.microsoft.com/zh-cn/library/ah19swz4.aspx)  
            3..结构用于封装由相关字段组成的组。因为结构是值类型,所以它们的分配效率要比类略高些(来自MSDN:http://msdn.microsoft.com/zh-cn/library/ms228600(v=vs.90).aspx)  
            4.结构还可以包含构造函数、常量、字段、方法、属性、索引器、运算符、事件和嵌套类型,但如果同时需要上述几种成员,则应当考虑改为使用类作为类型(MSDN:http://msdn.microsoft.com/zh-cn/library/ah19swz4.aspx)  
            5.类是反映现实事物的一种抽象,而结构体的作用只是一种包含了具体不同类别数据的一种包装,结构体不具备类的继承多态特性  综上所述,您也知道了吧,还是那句话,什么时候什么场景该用什么类型就要用什么类型。

    小结:  
        1.字段类型的定义,一定要符合实际,不要随便胡乱定义。要不然可能造成的后果,别人不理解您的程序,机器损失巨大性能。  
        2.class,struct,合适场景用合适的定义,不经意间提升你程序的性能。  
        3.程序进步、优雅,技能同时也会再进步,难道money还会少吗??

  • 相关阅读:
    7月25 SVN 提交报错 | mybatis like | 数据库字段设计 | 打包打小包
    7月24 springboot 打包打小包 | mybatis 逆向工程 | 接口返回数据 | 启动打包注意事项 | springboot redis 引入
    7月20号 添加字段报错 | 密码加密与传输
    7月19 登录失败 错误次数 | 字段类型被修改bug | 日志
    7月14 Enity对象的抽取
    7月13 mybatis调用存储过程
    7月12 导入项目到svn | logback配置日志输出
    7月11 配置数据库自己挖坑 | 代码覆盖率测试 | MockMvc 测试用例
    书架
    试题库问题
  • 原文地址:https://www.cnblogs.com/bjlhx/p/3760795.html
Copyright © 2020-2023  润新知