寻找性能更优秀的动态 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 ...
随机推荐
- JavaFX ImageView
例子1:显示4个狗头.正常显示左上角.右下角的狗头:右上角的狗头旋转180°,并设置了透明度:左下角的狗头旋转90°,也设置了透明度. 1 import javafx.application.Appl ...
- vue中,使用 es6的 ` 符号给字符串之间换行
我这里分功能是点击"复制范围",就相当于复制图上的坐标点一样的数据和格式: "复制功能"的代码如下: copyPoints() { const vm = thi ...
- DX12龙书 00 - 环境配置:通过 Visual Studio 2019 运行示例项目
0x00 安装 Visual Studio 2019 安装 Visual Studio 2019 以及相关组件. 注:安装组件时带的 Windows 10 SDK 可以在 Individual com ...
- Linux系统编程—管道
▋****1. 管道的概念 管道,又名「无名管理」,或「匿名管道」,管道是一种非常基本,也是使用非常频繁的IPC方式. 1.1 管道本质 管道的本质也是一种文件,不过是伪文件,实际上是一块内核缓冲区, ...
- 上帝视角一文理解JavaScript原型和原型链
本文呆鹅原创,原文地址:https://juejin.im/user/307518987058686/posts 前言 本文将从上帝角度讲解JS的世界,在这个过程中,大家就能完全理解JS的原型和原型链 ...
- day34 Pyhton 网络编程
一今日内容 # 函数 # 面向对象 # 进阶 # 网络编程 4 # 并发编程 6-7 # 概念 # 网络基础 # 局域网的概念 # 交换机和路由器的工作流程 # ip地址 # mac地址 # 子网掩码 ...
- 【模拟】CF 796C Bank Hacking
题目大意 洛谷链接 给定一棵带点权树,选出一个最佳的根节点,使得根节点的点权不变,它的儿子点权加1,其余点点权加2,并使最大点权最小,输出这个最小的最大点权. 其他见链接(懒). PS:原题面很不好总 ...
- Logstash 国内加速下载 转
Logstash. 国内直接从官网(https://www.elastic.co)下载比较困难,需要一些技术手段.这里提供一个国内的镜像下载地址列表,方便网友下载. 找不到想要的版本?您可以访问 索引 ...
- centos8下启用rc-local服务
一,centos8不建议写rc.local,默认启动时执行的命令放到何处? 以前我们会把linux开机执行的命令写入到/etc/rc.local 在centos8上系统不再建议我们写入到rc.loca ...
- 通透,23 个问题 TCP 疑难杂症全解析
每个时代,都不会亏待会学习的人. 在进入今天主题之前我先抛几个问题,这篇文章一共提出 23 个问题. TCP 握手一定是三次?TCP 挥手一定是四次? 为什么要有快速重传,超时重传不够用?为什么要有 ...