寻找性能更优秀的不可变小字典
Dictionary 是一个很常用的键值对管理数据结构。但是在性能要求严苛的情况下,字典的查找速度并不高。所以,我们需要更快的方案。
需求说明
这里,我们需要一个 PropertyInfo 和委托对应的映射关系,这样我们就可以存储《寻找性能更优秀的动态 Getter 和 Setter 方案》提到的委托。
因此,这个字典有这些特点:
这个字典一旦创建就不需要修改。
字典项目并不多,因为通常一个 class 不会有太多属性。
方案说明
方案 1,Switch 表达式法。使用表达式生成一个包含 switch case 语句的委托。
方案 2,数组跳表。我们知道,switch case 之所以比连续的 if else 要快的原因是因为其生成的 IL 中包含一个跳表算法。因此,如果我们有办法使用连续数字作为下标,以及一个数组。就可以在 C#中自己实现跳表。
知识要点
使用表达式创建委托
PropertyInfo 有一个 int MetadataToken 属性,根据目前的观察,可以知道在一个类型中的属性其 MetadataToken 似乎是连续的,因此可以取模后作为跳表的 key。
所谓的跳表,可以简单理解为,使用数组的下标来定位数组中的特定元素。
实现代码
这里,我们直接给出基准测试中使用的代码。
其中:
Directly 直接读,没有任何查找
ArrayIndex 数组跳表
SwitchExp 表达式生成 Switch 方案
Dic 传统字典方案
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using BenchmarkDotNet.Attributes;namespace Newbe.ObjectVisitor.BenchmarkTest
{[Config(typeof(Config))]public class FuncSearchTest{private Func<Yueluo, object>[] _target;private readonly Yueluo _yueluo;private readonly Func<Yueluo, string> _func;private readonly PropertyInfo _nameP;private readonly Func<PropertyInfo, Func<Yueluo, object>> _switcher;private readonly Dictionary<PropertyInfo, Func<Yueluo, object>> _dic;public FuncSearchTest(){_yueluo = Yueluo.Create();var propertyInfos = typeof(Yueluo).GetProperties().ToArray();CreateCacheArrayD(propertyInfos);_switcher = ValueGetter.CreateGetter<Yueluo, object>(propertyInfos,info => Expression.SwitchCase(Expression.Constant(CreateFunc(info)), Expression.Constant(info)));_dic = propertyInfos.ToDictionary(x => x, CreateFunc);_nameP = typeof(Yueluo).GetProperty(nameof(Yueluo.Name));_func = x => x.Name;}private void CreateCacheArrayD(IReadOnlyCollection<PropertyInfo> propertyInfos){_target = new Func<Yueluo, object>[propertyInfos.Count];foreach (var info in propertyInfos){var key = GetKey(info);var index = key % propertyInfos.Count;_target[index] = CreateFunc(info);}}private static Func<Yueluo, object> CreateFunc(PropertyInfo info){var pExp = Expression.Parameter(typeof(Yueluo), "x");var bodyExp = Expression.Property(pExp, info);var finalExp =Expression.Lambda<Func<Yueluo, object>>(Expression.Convert(bodyExp, typeof(object)), pExp);return finalExp.Compile();}private static int GetKey(MemberInfo info){var token = info.MetadataToken;return token;}[Benchmark(Baseline = true)]public string Directly() => _func(_yueluo);[Benchmark]public string ArrayIndex() => (string) _target[_nameP.MetadataToken % _target.Length](_yueluo);[Benchmark]public string SwitchExp() => (string) _switcher(_nameP)(_yueluo);[Benchmark]public string Dic() => (string) _dic[_nameP](_yueluo);}
}
基准测试
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
Intel Xeon CPU E5-2678 v3 2.50GHz, 1 CPU, 24 logical and 12 physical cores
.NET Core SDK=5.0.100-rc.2.20479.15[Host] : .NET Core 2.1.23 (CoreCLR 4.6.29321.03, CoreFX 4.6.29321.01), X64 RyuJITnet461 : .NET Framework 4.8 (4.8.4250.0), X64 RyuJITnet48 : .NET Framework 4.8 (4.8.4250.0), X64 RyuJITnetcoreapp21 : .NET Core 2.1.23 (CoreCLR 4.6.29321.03, CoreFX 4.6.29321.01), X64 RyuJITnetcoreapp31 : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJITnetcoreapp5 : .NET Core 5.0.0 (CoreCLR 5.0.20.47505, CoreFX 5.0.20.47505), X64 RyuJIT
结论
字典真拉胯。
Framework 真拉胯。
Net 5 简直太强了。
数组跳表是非直接方案中最快的。
图表
数据
Method | Job | Runtime | Mean | Error | StdDev | Ratio | RatioSD | Rank |
---|---|---|---|---|---|---|---|---|
Directly | net461 | .NET 4.6.1 | 0.9347 ns | 0.0363 ns | 0.0321 ns | 1.00 | 0.00 | 1 |
ArrayIndex | net461 | .NET 4.6.1 | 15.0904 ns | 0.3820 ns | 0.3752 ns | 16.13 | 0.64 | 2 |
SwitchExp | net461 | .NET 4.6.1 | 17.1585 ns | 0.0624 ns | 0.0521 ns | 18.30 | 0.56 | 3 |
Dic | net461 | .NET 4.6.1 | 34.3348 ns | 0.2447 ns | 0.2169 ns | 36.77 | 1.18 | 4 |
Directly | net48 | .NET 4.8 | 0.6338 ns | 0.0233 ns | 0.0218 ns | 1.00 | 0.00 | 1 |
ArrayIndex | net48 | .NET 4.8 | 15.3098 ns | 0.2794 ns | 0.2613 ns | 24.17 | 0.69 | 2 |
SwitchExp | net48 | .NET 4.8 | 17.8113 ns | 0.0740 ns | 0.0656 ns | 28.20 | 0.98 | 3 |
Dic | net48 | .NET 4.8 | 33.7930 ns | 0.4538 ns | 0.4245 ns | 53.36 | 1.64 | 4 |
Directly | netcoreapp21 | .NET Core 2.1 | 1.2153 ns | 0.1168 ns | 0.1434 ns | 1.00 | 0.00 | 1 |
ArrayIndex | netcoreapp21 | .NET Core 2.1 | 4.6545 ns | 0.1044 ns | 0.0871 ns | 4.01 | 0.51 | 2 |
SwitchExp | netcoreapp21 | .NET Core 2.1 | 8.1995 ns | 0.2567 ns | 0.2747 ns | 6.81 | 0.90 | 3 |
Dic | netcoreapp21 | .NET Core 2.1 | 24.2669 ns | 0.5440 ns | 0.5586 ns | 20.07 | 2.51 | 4 |
Directly | netcoreapp31 | .NET Core 3.1 | 0.7382 ns | 0.1148 ns | 0.1074 ns | 1.00 | 0.00 | 1 |
ArrayIndex | netcoreapp31 | .NET Core 3.1 | 4.3580 ns | 0.1299 ns | 0.1085 ns | 6.10 | 0.77 | 2 |
SwitchExp | netcoreapp31 | .NET Core 3.1 | 7.5985 ns | 0.1310 ns | 0.1161 ns | 10.45 | 1.41 | 3 |
Dic | netcoreapp31 | .NET Core 3.1 | 22.2433 ns | 0.2756 ns | 0.2443 ns | 30.61 | 4.20 | 4 |
Directly | netcoreapp5 | .NET Core 5.0 | 1.3323 ns | 0.0527 ns | 0.0493 ns | 1.00 | 0.00 | 1 |
ArrayIndex | netcoreapp5 | .NET Core 5.0 | 5.0058 ns | 0.1361 ns | 0.1206 ns | 3.77 | 0.15 | 2 |
SwitchExp | netcoreapp5 | .NET Core 5.0 | 9.0576 ns | 0.0985 ns | 0.0921 ns | 6.81 | 0.26 | 3 |
Dic | netcoreapp5 | .NET Core 5.0 | 20.4052 ns | 0.2724 ns | 0.2275 ns | 15.44 | 0.59 | 4 |
总结
不论是数组跳表还是表达式 Switch 方案都可以解决这个问题,而且都要比使用字典要快。
但是这里有一个问题,就是目前作者还没有找到任何有关 MetadataToken 是否真的具备同 class 连续的性质。
因此建议还是使用 Switch 方案实现。
我只是知识的搬运工
- [Working with Expression Trees in C#](https://tyrrrz.me/blog/expression-trees)
寻找性能更优秀的不可变小字典相关推荐
- 寻找性能更优秀的动态 Getter 和 Setter 方案
反射获取 PropertyInfo 可以对对象的属性值进行读取或者写入,但是这样性能不好.所以,我们需要更快的方案. 方案说明 就是用表达式编译一个Action<TObj,TValue>作 ...
- 计算机专业独显好还是集显好,集成显卡和独立显卡有什么区别?哪个性能更好?...
电脑的硬件非常多,比如:主板.硬盘.显卡.鼠标等,不少用户买电脑的时候都会考虑到这些硬件,所以今天小编特意挑出一个硬件来讲,那就是显卡,显卡又分为两类,一个是集成显卡,一个是独立显卡,那么集成显卡和独 ...
- spyder pyecharts不显示_逆袭的IGZO-IPS小金刚!微星PAG272QRZ显示器评测:色域、响应速度更优秀...
一.前言:小金刚市场再添新选手 IGZO-IPS来了 过去几年,各大厂商围绕着27寸2K高刷新率IPS面板这一标准,推出了大量"小金刚"规格的电竞显示器.同时,群创.友达和LGD这 ...
- python效率numpy_Python数据处理性能对比,原生,Pandas,Numpy哪个更优秀
原标题:Python数据处理性能对比,原生,Pandas,Numpy哪个更优秀 今天为大家分享一个关于数据处理性能的对比,从原生,Pandas ,Numpy这三个方面对比?你觉得哪个更优秀呢?对于一个 ...
- Python数据处理性能对比,原生,Pandas,Numpy哪个更优秀
https://blog.csdn.net/sinat_38682860/article/details/85765308 今天为大家分享一个关于数据处理性能的对比,从原生,Pandas ,Numpy ...
- 哈佛计算机系小哥哥中文字幕,【哈佛学霸小哥哥的一天】同样的24小时,为什么他们更优秀...
原标题:[哈佛学霸小哥哥的一天]同样的24小时,为什么他们更优秀 暑假过半, 不知道放假之初, 那些雄心勃勃的暑期计划完成了多少呢? "我家孩子写作业慢,暑假过半,作业本还没打开!" ...
- 提高ADO性能的优秀经验
一.概述 "性能"这一术语有着几种不同的.差异微妙的含义.当人们谈到某个东西性能多少好时,他们想要表达的意思可能就是在一定的时间之内它完成了多少工作.例如,一个性能好的发动机运行起 ...
- [美文]你懂得这些,才可能比别人更优秀!
你懂得这些,才可能比别人更优秀! 自2020年以来由于疫情的影响,大批量的公司破产倒闭,即使能坚持下来的,也是推出了很多财务削减和人员裁减计划(美其名曰: 人员优化),这导致了大量各行各业人员的失业, ...
- mPaaS:全新移动开发平台,只为打造性能更优越的App
简介: 基于移动开发现状与技术演进预判,提供移动开发强力解决方案,洞察 mPaaS 如何帮助企业有效降低技术门槛,减少研发成本,搭建更稳定.更流畅的移动 App. mPaaS 是源自于支付宝的移动开发 ...
最新文章
- python爬虫自学笔记分析解密_python爬虫学习笔记——1 各种文本分析工具简介之汇总...
- windows下挂载ext4_WSL2 支持挂载物理磁盘,Windows 可直接访问 ext4
- C++的高效从何而来
- 利用云计算打造政务信息化及应急指挥云平台
- git重命名远程仓库名字 同步fork代码
- java中HashSet对象内的元素的hashCode值不能变化
- Kali Linux Network Scanning Cookbook读书笔记之nmap
- jquery ajax和servlet,浅谈ajax在jquery中的请求和servlet中的响应
- 用c#算成绩的总和_用c#编写输出成绩的总分和平均分
- Rust: codewars的Roman Numerals Encoder
- java游戏2333整合包,3dm游戏运行库合集离线安装包
- 【计算机系统基础】- 袁春风
- 无线网络的暴力破解密码
- 高斯过程回归(GPR)
- Windows 2000 安全检查清单( 摘自《网络与安全》)
- 蓝色学校网站模板_中小学网站源码_学校网站管理系统
- android blowfish加密算法,blowfish 现在哪种加密算法安全?A
- Java 发送邮件的几种方式
- 中国医疗器械行业需求态势及未来前景趋势预测报告(2022-2027年)
- Java生成二维码图片,手机软件扫码后跳转网页
热门文章
- zbb20180710 maven Failed to read artifact descriptor--maven
- 62、滑动窗口的最大值
- iOS duplicate symbol for architecture arm64 解决办法
- C#集合类型——Array、ArrayList、List 之浅谈
- 6 四大组件之Service
- android 系统之ContentProvider
- 使用PowerShell配置Microsoft Teams
- nest 架构_当有人打来您的Nest Hello时,如何让Google Home通知您
- php获取一个文件名的函数,PHP 文件系统函数之获取文件名及文件名后缀-php文件...
- Android 干货,强烈推荐