寻找性能更优秀的动态 Getter 和 Setter 方案
反射获取 PropertyInfo 可以对对象的属性值进行读取或者写入,但是这样性能不好。所以,我们需要更快的方案。
方案说明
就是用表达式编译一个 Action<TObj,TValue>
作为 Setter,编译一个 Func<TObj,TValue>
作为 Getter。
然后把这些编译好的委托放在一个泛型类的静态字段中保存起来,需要使用的时候从这里面查找就可以了。
知识要点
- 使用表达式创建委托
- 泛型类的静态字段是每个闭合类型独立的,因此用于存储和类型相关的内容非常方便
实现代码
由于代码中混合的使用 Switch 作为字典的阴招,所以代码很长,此处不再罗列,仅给出链接:
基准测试
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1) |
结论
- 使用委托明显比使用 PropertyInfo 要快,这个方案可以。
- Framework 真拉胯,Net 5 简直太强了。
- 如果属性是明确的,建议把字典中取出来的委托保存在自己的上下文,这可以明显的省去查找的消耗。
图表
从左往右分别是:直接读取属性、缓存委托、不缓存委托和使用 PropertyInfo。
数据
Getter
Method | Job | Runtime | Mean | Error | StdDev | Median | Ratio | RatioSD | Rank |
---|---|---|---|---|---|---|---|---|---|
DirectlyString | net461 | .NET 4.6.1 | 0.1636 ns | 0.0822 ns | 0.1126 ns | 0.1472 ns | ? | ? | 2 |
DirectlyInt | net461 | .NET 4.6.1 | 0.0318 ns | 0.0348 ns | 0.0342 ns | 0.0217 ns | ? | ? | 1 |
ReflectString | net461 | .NET 4.6.1 | 145.8375 ns | 2.2790 ns | 2.1317 ns | 145.6522 ns | ? | ? | 7 |
ReflectInt | net461 | .NET 4.6.1 | 172.5066 ns | 1.3206 ns | 1.1028 ns | 172.6804 ns | ? | ? | 8 |
GetterString | net461 | .NET 4.6.1 | 31.4379 ns | 0.6017 ns | 0.5334 ns | 31.6316 ns | ? | ? | 4 |
GetterInt | net461 | .NET 4.6.1 | 33.0642 ns | 0.4940 ns | 0.4380 ns | 33.0557 ns | ? | ? | 5 |
GetterObject | net461 | .NET 4.6.1 | 33.9174 ns | 0.5587 ns | 0.5226 ns | 33.7326 ns | ? | ? | 6 |
GetterCached | net461 | .NET 4.6.1 | 7.5878 ns | 0.1223 ns | 0.1144 ns | 7.5765 ns | ? | ? | 3 |
DirectlyString | net48 | .NET 4.8 | 0.0181 ns | 0.0353 ns | 0.0313 ns | 0.0043 ns | ? | ? | 1 |
DirectlyInt | net48 | .NET 4.8 | 0.0050 ns | 0.0089 ns | 0.0079 ns | 0.0000 ns | ? | ? | 1 |
ReflectString | net48 | .NET 4.8 | 143.8313 ns | 2.2501 ns | 2.1047 ns | 143.5568 ns | ? | ? | 5 |
ReflectInt | net48 | .NET 4.8 | 172.1714 ns | 1.9819 ns | 1.7569 ns | 172.3142 ns | ? | ? | 6 |
GetterString | net48 | .NET 4.8 | 31.5887 ns | 0.6310 ns | 0.5902 ns | 31.5385 ns | ? | ? | 3 |
GetterInt | net48 | .NET 4.8 | 32.7140 ns | 0.3992 ns | 0.3734 ns | 32.7343 ns | ? | ? | 4 |
GetterObject | net48 | .NET 4.8 | 33.3063 ns | 0.2069 ns | 0.1834 ns | 33.3053 ns | ? | ? | 4 |
GetterCached | net48 | .NET 4.8 | 7.5540 ns | 0.2201 ns | 0.1951 ns | 7.5069 ns | ? | ? | 2 |
DirectlyString | netcoreapp21 | .NET Core 2.1 | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.0000 ns | ? | ? | 1 |
DirectlyInt | netcoreapp21 | .NET Core 2.1 | 0.0193 ns | 0.0111 ns | 0.0104 ns | 0.0177 ns | ? | ? | 2 |
ReflectString | netcoreapp21 | .NET Core 2.1 | 110.4180 ns | 2.2159 ns | 1.8503 ns | 110.8038 ns | ? | ? | 7 |
ReflectInt | netcoreapp21 | .NET Core 2.1 | 138.9612 ns | 0.9694 ns | 0.8594 ns | 138.8217 ns | ? | ? | 8 |
GetterString | netcoreapp21 | .NET Core 2.1 | 16.8958 ns | 0.2384 ns | 0.2230 ns | 16.8103 ns | ? | ? | 4 |
GetterInt | netcoreapp21 | .NET Core 2.1 | 19.4407 ns | 0.2041 ns | 0.1809 ns | 19.4539 ns | ? | ? | 6 |
GetterObject | netcoreapp21 | .NET Core 2.1 | 18.6922 ns | 0.2700 ns | 0.2255 ns | 18.6582 ns | ? | ? | 5 |
GetterCached | netcoreapp21 | .NET Core 2.1 | 0.9299 ns | 0.0457 ns | 0.0427 ns | 0.9308 ns | ? | ? | 3 |
DirectlyString | netcoreapp31 | .NET Core 3.1 | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.0000 ns | ? | ? | 1 |
DirectlyInt | netcoreapp31 | .NET Core 3.1 | 0.0693 ns | 0.0102 ns | 0.0091 ns | 0.0709 ns | ? | ? | 2 |
ReflectString | netcoreapp31 | .NET Core 3.1 | 98.6735 ns | 0.8335 ns | 0.7389 ns | 98.5319 ns | ? | ? | 7 |
ReflectInt | netcoreapp31 | .NET Core 3.1 | 130.6941 ns | 0.9332 ns | 0.8730 ns | 130.5376 ns | ? | ? | 8 |
GetterString | netcoreapp31 | .NET Core 3.1 | 14.8915 ns | 0.2025 ns | 0.1795 ns | 14.8911 ns | ? | ? | 4 |
GetterInt | netcoreapp31 | .NET Core 3.1 | 16.2874 ns | 0.0789 ns | 0.0700 ns | 16.2753 ns | ? | ? | 5 |
GetterObject | netcoreapp31 | .NET Core 3.1 | 17.6202 ns | 0.1130 ns | 0.1057 ns | 17.6092 ns | ? | ? | 6 |
GetterCached | netcoreapp31 | .NET Core 3.1 | 0.6351 ns | 0.0244 ns | 0.0217 ns | 0.6393 ns | ? | ? | 3 |
DirectlyString | netcoreapp5 | .NET Core 5.0 | 0.5098 ns | 0.0328 ns | 0.0291 ns | 0.5131 ns | 1.000 | 0.00 | 2 |
DirectlyInt | netcoreapp5 | .NET Core 5.0 | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.000 | 0.00 | 1 |
ReflectString | netcoreapp5 | .NET Core 5.0 | 88.8937 ns | 0.9697 ns | 0.8596 ns | 88.7457 ns | 174.838 | 9.26 | 7 |
ReflectInt | netcoreapp5 | .NET Core 5.0 | 123.4464 ns | 1.0582 ns | 0.9898 ns | 123.3193 ns | 242.996 | 14.00 | 8 |
GetterString | netcoreapp5 | .NET Core 5.0 | 7.6628 ns | 0.0931 ns | 0.0777 ns | 7.6703 ns | 15.031 | 0.95 | 5 |
GetterInt | netcoreapp5 | .NET Core 5.0 | 6.6645 ns | 0.0825 ns | 0.0772 ns | 6.6497 ns | 13.085 | 0.69 | 4 |
GetterObject | netcoreapp5 | .NET Core 5.0 | 8.3090 ns | 0.1685 ns | 0.1576 ns | 8.2865 ns | 16.344 | 0.83 | 6 |
GetterCached | netcoreapp5 | .NET Core 5.0 | 0.9791 ns | 0.0293 ns | 0.0245 ns | 0.9764 ns | 1.920 | 0.13 | 3 |
Setter
Method | Job | Runtime | Mean | Error | StdDev | Median | Ratio | RatioSD | Rank |
---|---|---|---|---|---|---|---|---|---|
DirectlyString | net461 | .NET 4.6.1 | 2.0161 ns | 0.0300 ns | 0.0266 ns | 2.0045 ns | 1.000 | 0.00 | 2 |
DirectlyInt | net461 | .NET 4.6.1 | 0.0076 ns | 0.0094 ns | 0.0083 ns | 0.0081 ns | 0.004 | 0.00 | 1 |
ReflectString | net461 | .NET 4.6.1 | 237.5006 ns | 4.5706 ns | 4.4890 ns | 236.5912 ns | 117.871 | 3.40 | 5 |
ReflectInt | net461 | .NET 4.6.1 | 249.3627 ns | 2.1717 ns | 2.0314 ns | 249.0283 ns | 123.681 | 1.94 | 6 |
GetterString | net461 | .NET 4.6.1 | 32.8621 ns | 0.2855 ns | 0.2229 ns | 32.9189 ns | 16.335 | 0.22 | 4 |
GetterInt | net461 | .NET 4.6.1 | 33.6103 ns | 0.4245 ns | 0.3544 ns | 33.5499 ns | 16.695 | 0.26 | 4 |
GetterObject | net461 | .NET 4.6.1 | 33.2561 ns | 0.2966 ns | 0.2629 ns | 33.1795 ns | 16.497 | 0.17 | 4 |
GetterCached | net461 | .NET 4.6.1 | 9.1805 ns | 0.0761 ns | 0.0674 ns | 9.1802 ns | 4.554 | 0.08 | 3 |
DirectlyString | net48 | .NET 4.8 | 1.9272 ns | 0.0298 ns | 0.0264 ns | 1.9245 ns | 1.000 | 0.00 | 2 |
DirectlyInt | net48 | .NET 4.8 | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.000 | 0.00 | 1 |
ReflectString | net48 | .NET 4.8 | 237.7686 ns | 4.6597 ns | 5.3661 ns | 235.8445 ns | 123.908 | 3.57 | 5 |
ReflectInt | net48 | .NET 4.8 | 249.6291 ns | 4.5333 ns | 4.2404 ns | 249.5459 ns | 129.689 | 3.13 | 6 |
GetterString | net48 | .NET 4.8 | 32.2366 ns | 0.1941 ns | 0.1721 ns | 32.1780 ns | 16.731 | 0.29 | 4 |
GetterInt | net48 | .NET 4.8 | 32.0081 ns | 0.1488 ns | 0.1162 ns | 32.0270 ns | 16.572 | 0.23 | 4 |
GetterObject | net48 | .NET 4.8 | 32.6413 ns | 0.1417 ns | 0.1183 ns | 32.6260 ns | 16.907 | 0.24 | 4 |
GetterCached | net48 | .NET 4.8 | 9.2589 ns | 0.0928 ns | 0.0868 ns | 9.2564 ns | 4.799 | 0.07 | 3 |
DirectlyString | netcoreapp21 | .NET Core 2.1 | 2.4107 ns | 0.0507 ns | 0.0475 ns | 2.3936 ns | 1.000 | 0.00 | 2 |
DirectlyInt | netcoreapp21 | .NET Core 2.1 | 0.0007 ns | 0.0028 ns | 0.0025 ns | 0.0000 ns | 0.000 | 0.00 | 1 |
ReflectString | netcoreapp21 | .NET Core 2.1 | 203.6637 ns | 3.6109 ns | 3.3777 ns | 203.4793 ns | 84.517 | 2.31 | 7 |
ReflectInt | netcoreapp21 | .NET Core 2.1 | 213.8619 ns | 2.1882 ns | 1.9398 ns | 213.7367 ns | 88.757 | 1.71 | 8 |
GetterString | netcoreapp21 | .NET Core 2.1 | 19.5240 ns | 0.0811 ns | 0.0758 ns | 19.5149 ns | 8.102 | 0.15 | 5 |
GetterInt | netcoreapp21 | .NET Core 2.1 | 18.8794 ns | 0.1193 ns | 0.1058 ns | 18.8837 ns | 7.836 | 0.18 | 4 |
GetterObject | netcoreapp21 | .NET Core 2.1 | 20.6765 ns | 0.2709 ns | 0.2115 ns | 20.6419 ns | 8.584 | 0.14 | 6 |
GetterCached | netcoreapp21 | .NET Core 2.1 | 2.7606 ns | 0.0613 ns | 0.0512 ns | 2.7590 ns | 1.148 | 0.02 | 3 |
DirectlyString | netcoreapp31 | .NET Core 3.1 | 2.2625 ns | 0.0647 ns | 0.0605 ns | 2.2555 ns | 1.000 | 0.00 | 2 |
DirectlyInt | netcoreapp31 | .NET Core 3.1 | 0.0072 ns | 0.0165 ns | 0.0146 ns | 0.0000 ns | 0.003 | 0.01 | 1 |
ReflectString | netcoreapp31 | .NET Core 3.1 | 182.7306 ns | 3.3249 ns | 3.1101 ns | 182.3062 ns | 80.804 | 1.99 | 7 |
ReflectInt | netcoreapp31 | .NET Core 3.1 | 192.2510 ns | 2.3691 ns | 2.1002 ns | 191.4821 ns | 85.061 | 2.88 | 8 |
GetterString | netcoreapp31 | .NET Core 3.1 | 16.9918 ns | 0.2115 ns | 0.1979 ns | 16.9651 ns | 7.516 | 0.25 | 5 |
GetterInt | netcoreapp31 | .NET Core 3.1 | 16.1168 ns | 0.3558 ns | 0.3654 ns | 15.9822 ns | 7.138 | 0.19 | 4 |
GetterObject | netcoreapp31 | .NET Core 3.1 | 19.3060 ns | 0.4173 ns | 0.5571 ns | 19.4856 ns | 8.480 | 0.45 | 6 |
GetterCached | netcoreapp31 | .NET Core 3.1 | 2.9276 ns | 0.0156 ns | 0.0146 ns | 2.9313 ns | 1.295 | 0.03 | 3 |
DirectlyString | netcoreapp5 | .NET Core 5.0 | 2.2455 ns | 0.0084 ns | 0.0078 ns | 2.2460 ns | 1.000 | 0.00 | 2 |
DirectlyInt | netcoreapp5 | .NET Core 5.0 | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.000 | 0.00 | 1 |
ReflectString | netcoreapp5 | .NET Core 5.0 | 162.8780 ns | 0.7135 ns | 0.6674 ns | 162.8741 ns | 72.538 | 0.45 | 7 |
ReflectInt | netcoreapp5 | .NET Core 5.0 | 171.1380 ns | 0.4173 ns | 0.3699 ns | 171.1414 ns | 76.217 | 0.31 | 8 |
GetterString | netcoreapp5 | .NET Core 5.0 | 8.6244 ns | 0.1891 ns | 0.1769 ns | 8.5469 ns | 3.841 | 0.08 | 5 |
GetterInt | netcoreapp5 | .NET Core 5.0 | 6.5511 ns | 0.0347 ns | 0.0325 ns | 6.5634 ns | 2.917 | 0.02 | 4 |
GetterObject | netcoreapp5 | .NET Core 5.0 | 9.0732 ns | 0.0306 ns | 0.0272 ns | 9.0735 ns | 4.041 | 0.02 | 6 |
GetterCached | netcoreapp5 | .NET Core 5.0 | 2.8223 ns | 0.0728 ns | 0.0681 ns | 2.8190 ns | 1.257 | 0.03 | 3 |
总结
使用表达式创建委托来取代 PropertyInfo 读取和写入属性效果很好。
开发者也可以直接引用 Newbe.ObjectVisitor 包来使用已经封装好的 ValueGetter 和 ValueSetter。
我只是知识的搬运工
- 晚绑定场景下对象属性赋值和取值可以不需要 PropertyInfo
- 三种属性操作性能比较:PropertyInfo + Expression Tree + Delegate.CreateDelegate
- 关于 Expression Tree 和 IL Emit 的所谓的” 性能差别”
发布说明
使用样例
番外分享
GitHub 项目地址:https://github.com/newbe36524/Newbe.ObjectVisitor
Gitee 项目地址:https://gitee.com/yks/Newbe.ObjectVisitor
- 本文作者: newbe36524
- 本文链接: https://www.newbe.pro/Newbe.ObjectVisitor/Better-Performance-Getter-Setter/
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
寻找性能更优秀的动态 Getter 和 Setter 方案的更多相关文章
- Stylus-NodeJS下构建更富表现力/动态/健壮的CSS
--------------------------本文来自张鑫旭大神博客------------------------------ 一.为什么我会讲Stylus,而不是SASS和LESS? SAS ...
- 比Kafka Mangaer更优秀的开源监控工具-Kafka Eagle
比Kafka Mangaer更优秀的开源监控工具-Kafka Eagle 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在Kafka的监控系统中有很多优秀的开源监控系统.比如Kaf ...
- 通过AI自学习,Google让Pixel 3的人像模式更优秀
通过AI自学习,Google让Pixel 3的人像模式更优秀 Link: https://news.cnblogs.com/n/613720/ 虽然双摄手机已经在市场上普及,其所带来的人像模式.多倍变 ...
- Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%。再往后,每提高0.1%,优化难度成指数级增长了。哪怕是千分之一,也直接影响用户体验,影响每天上万张机票的销售额。 在高并发场景下,提供了保证线程安全的对象、方法。比如经典的ConcurrentHashMap,它比起HashMap,有更小粒度的锁,并发读写性能更好。线程安全的StringBuilder取代S
Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%.再往后,每提高0.1%,优化难度成指数级增长了.哪怕是千分之一,也直接影响用户体验,影响每天上万张机 ...
- Ember.js和Vue.js对比,哪个框架更优秀?
本文由葡萄城技术团队于博客园翻译并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. JavaScript最初是为Web应用程序创建的.但是随着前端技术的 ...
- 异步IO比同步阻塞IO性能更好吗?为什么?
最近在看node.js, 介绍中提到node是异步io的方式实现, 性能比同步阻塞io的更好. 对于一个request而言, 如果我们依赖io的结果, 异步io和同步阻塞io都是要等到io完成才能继续 ...
- PHP日志扩展 SeasLog-1.6.8, 性能更优
SeasLog-1.6.8 发布了,性能更优. 改进日志: 1.6.8: 优化内存使用和性能,修复已知Bug. - Fixed issue #97 PHP5.* Cached Block. - Fix ...
- 能让你成为更优秀程序员的10个C语言资源
能让你成为更优秀程序员的10个C语言资源 本文由 伯乐在线 - archychu 翻译自 mycplus.欢迎加入 技术翻译小组.转载请参见文章末尾处的要求. 一些人觉得编程无聊,一些人觉得它很好玩. ...
- graphicview和widgets没本质区别。它只是更轻量级,更灵活,性能更高的widgets
graphicview和widgets没本质区别.它只是更轻量级,更灵活,性能更高的widgets.核心就是把widgets变成了更轻量级的graphicitem,把QWidget的各种事件转换成了g ...
随机推荐
- 05 C语言的数据类型
C语言的数据类型 在C 中,数据类型是用来声明不同类型的变量或函数的一个广泛的概念.变量的数据类型决定了变量存储占用的空间大小,以及如何去解释存储的位模式. C 中的数据类型可分为以下几大类: 序号 ...
- 微服务 | Spring Cloud(一):从单体SSM 到 Spring Cloud
系列文章目录 微服务 | Spring Cloud(一):从单体SSM 到 Spring Cloud 目录 系列文章目录 前言 单体式架构 微服务架构 优点 缺点 服务发现与弹性扩展 参考 前言 在微 ...
- vue : 无法加载文件 C:\Users\Lenovo\AppData\Roaming\npm\vue.ps1,因为在此系统上禁止运行脚本。
第一步:用管理员身份打开 第二步:执行:set-ExecutionPolicy RemoteSigned 选择Y或A,回车
- Linux init 详解(0,1,2,3,4,5,6)
一.什么是 init init是Linux系统操作中不可缺少的程序之一. 所谓的init进程,它是一个由内核启动的用户级进程. 内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数 ...
- RHSA-2017:2930-重要: 内核 安全和BUG修复更新(需要重启、存在EXP、本地提权、代码执行)
[root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) 修复命令: 使用root账号登陆She ...
- ORA-00019: maximum number of session licenses exceeded 超出最大会话许可数
ORA-00019: maximum number of session licenses exceededORA-00019: 超出最大会话许可数 Cause: All licenses ...
- C# 软件版本号
如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! --------------------------- ...
- Swoole实时任务异步调用Demo
server.php <?php class Server { private $serv; private $logFilePath = "/data/wwwroot/houtai/ ...
- CVE-2010-2883-CoolType.dll缓冲区溢出漏洞分析
前言 此漏洞是根据泉哥的<漏洞战争>来学习分析的,网上已有大量分析文章在此只是做一个独立的分析记录. 复现环境 操作系统 -> Windows XP Sp3 软件版本 -> A ...
- Thumbnailator处理图片
读取源图 of(String... files) of(File... files) of(InputStream... inputStreams) of(URL... urls) 输出文件 toFi ...