什么时候我们应谈及性能?

开发 项目管理
此文意非强调不能用反射,网上讨论也很多,还是老话,根据实际业务情况,具体分析,别整体就惦记和揪着性能不放,比如针对快递行业,导入和导出操作可谓再正常不过,其导入数量也是庞大,对于此种情况,我们是否可考虑通过结构体存储数据呢?

[[379516]]

本文转载自微信公众号「JeffckyShare」,作者Jeffcky 。转载本文请联系JeffckyShare公众号。   

个人以为,性能并非一次性就可完全成全,需结合实际业务有一个大致评估或预期,比如数据量大小,若预期短暂并不会达到性能瓶颈,大可不必过度考虑,又或者根据自我假想可能存在性能问题,于是大张旗鼓陷入自我意识流,最终可能结果吃亏反而不讨好。

项目性能考虑

此前我个人写过一版Excel导入和导出,并未使用对应开源组件,因为导出和导入逻辑并不复杂,不涉及单元格拆分、包含图片、下拉框等等,但处理起来也并没有什么难度,借助NPOI或EPPLUS工具皆可满足。

于是我尝试将此前封装Excel导入和导出做了进一步重构处理,主要为解决此前遗留问题:

其一:表头列和实体属性列顺序必须一一对应

其二:导出由于Excel单个Sheet行有限制,超出一定行,必须重建Sheet

其三:大量使用反射,若存在多个Sheet,且每个Sheet行数量稍微巨大,则存在一定性能瓶颈

如上两点可以简单解决,这里我们忽略,问题在于第三点,因为使用泛型,针对每一行读取都会反射对象,同时也要获取其实例属性并赋值,这里我们完全可以改善下性能

接下来,我们通过一个简单例子,来演示如何改善反射性能,当然,也还有其他方案,这里我只介绍我个人的方案

反射性能改善

如一部分开源组件一样,我们通过特性标识属性,属性名称和表头列匹配,顺序无需一致,同样,属性可忽略赋值

基于上述情况,我们要获取对应实体所标识的属性特性,这里为便于后续属性赋值,我们缓存属性相关信息,避免频繁通过反射获取属性信息

接下来,我们来到属性赋值和获取,我们以设置值为例,获取值同理,同时以1万作为基数来验证,然后以此基数递增,如下测试实体

  1. public class Test 
  2.  public int Id { get; set; } 
  3.  public string Name { get; set; } 

反射属性赋值示例,如下:

  1. static void ReflectionExample(int count
  2.     var stopWatch = new Stopwatch(); 
  3.     stopWatch.Start(); 
  4.  
  5.     var tests = Enumerable.Repeat(new Test(), count).ToList(); 
  6.  
  7.     var propertyIdInfo = typeof(Test).GetProperty("Id"); 
  8.     var propertyNameInfo = typeof(Test).GetProperty("Name"); 
  9.  
  10.     foreach (var test in tests) 
  11.     { 
  12.         propertyIdInfo.SetValue(test, 1); 
  13.         propertyNameInfo.SetValue(test, "jeffcky"); 
  14.     } 
  15.  
  16.     Console.WriteLine($"反射赋值耗时:{stopWatch.ElapsedMilliseconds}ms"); 

 

 


 

 

当然,根据笔记本配置以及所使用耗时方案不标准,结果会存在差异,但基本可判断反射耗时会有20ms以上

接下来,我使用委托方式来直接调用属性Set方法,看看性能是否会有改善

  1. static void DelegateExample(int count
  2.     var stopWatch = new Stopwatch(); 
  3.     stopWatch.Start(); 
  4.  
  5.     var tests = Enumerable.Repeat(new Test(), count).ToList(); 
  6.  
  7.     var setId = (Action<Test, int>)Delegate.CreateDelegate(typeof(Action<Test, int>), null,  
  8.       typeof(Test).GetProperty("Id").GetSetMethod()); 
  9.  
  10.     var setName = (Action<Test, string>)Delegate.CreateDelegate(typeof(Action<Test, string>), null
  11.       typeof(Test).GetProperty("Name").GetSetMethod()); 
  12.  
  13.     foreach (var test in tests) 
  14.     { 
  15.         setId(test, 3); 
  16.         setName(test, "jeffcky"); 
  17.     } 
  18.  
  19.     Console.WriteLine($"委托赋值耗时:{stopWatch.ElapsedMilliseconds}ms"); 

接下来,我们对比反射1万条数据属性赋值,看看耗时情况怎样

 

通过运行多次,通过调用委托赋值其耗时基本可控制在5ms以内,想想差距还是有点大,接下来我们将数据量直接上升到100万看看其差距

 

结果显而易见,通过反射耗时将超过1s,而委托赋值则控制在几十ms,如果再加上属性的个数和获取属性值,耗时时间势必将会再一次拉大

为何很多人都说反射性能很差,因为引入反射会通过如下几步对性能有巨大损耗

其一:检查所调用方法是否存在

其二:检查其安全性和访问可见性

其三:检查签名,确保所提供的参数和类型的数量与方法定义签名一致

其四:解出参数

此文意非强调不能用反射,网上讨论也很多,还是老话,根据实际业务情况,具体分析,别整体就惦记和揪着性能不放,比如针对快递行业,导入和导出操作可谓再正常不过,其导入数量也是庞大,对于此种情况,我们是否可考虑通过结构体存储数据呢?一切皆通过实际场景出发。

那么问题来了,写本文的目的是什么呢?

责任编辑:武晓燕 来源: JeffckyShare
相关推荐

2012-07-26 10:27:31

PHP

2023-03-29 15:01:43

微服务开发

2020-05-12 11:25:50

MySQLES数据库

2017-05-15 09:55:07

2022-06-27 16:55:30

5G6G

2015-07-08 15:55:01

NSStringcopystrong

2024-09-02 08:53:44

2012-09-24 10:20:39

JavaScriptJS

2013-11-28 16:03:24

2024-08-05 01:22:16

2022-05-19 10:27:34

机器学习人工智能

2017-06-28 15:06:51

PythonLambda函数

2021-08-13 11:31:23

HTTP

2021-09-29 09:24:21

GCGo STW

2015-10-20 15:59:57

注释代码程序

2015-10-26 09:38:52

避免注释代码

2019-12-24 11:19:44

容器DockerLinux

2023-06-06 16:54:00

2011-10-18 16:41:23

编程

2017-04-05 21:43:08

MQ互联网架构
点赞
收藏

51CTO技术栈公众号