Dictionary 是一个很常用的键值对管理数据结构。但是在性能要求严苛的情况下,字典的查找速度并不高。所以,我们需要更快的方案。

需求说明

这里,我们需要一个 PropertyInfo 和委托对应的映射关系,这样我们就可以存储《寻找性能更优秀的动态 Getter 和 Setter 方案》提到的委托。

因此,这个字典有这些特点:

  1. 这个字典一旦创建就不需要修改。

  2. 字典项目并不多,因为通常一个 class 不会有太多属性。

方案说明

方案 1,Switch 表达式法。使用表达式生成一个包含 switch case 语句的委托。

方案 2,数组跳表。我们知道,switch case 之所以比连续的 if else 要快的原因是因为其生成的 IL 中包含一个跳表算法。因此,如果我们有办法使用连续数字作为下标,以及一个数组。就可以在 C#中自己实现跳表。

知识要点

  1. 使用表达式创建委托

  2. PropertyInfo 有一个 int MetadataToken 属性,根据目前的观察,可以知道在一个类型中的属性其 MetadataToken 似乎是连续的,因此可以取模后作为跳表的 key。

  3. 所谓的跳表,可以简单理解为,使用数组的下标来定位数组中的特定元素。

实现代码

这里,我们直接给出基准测试中使用的代码。

其中:

  • 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

结论

  1. 字典真拉胯。

  2. Framework 真拉胯。

  3. Net 5 简直太强了。

  4. 数组跳表是非直接方案中最快的。

图表

FuncSearch

数据

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)

寻找性能更优秀的不可变小字典相关推荐

  1. 寻找性能更优秀的动态 Getter 和 Setter 方案

    反射获取 PropertyInfo 可以对对象的属性值进行读取或者写入,但是这样性能不好.所以,我们需要更快的方案. 方案说明 就是用表达式编译一个Action<TObj,TValue>作 ...

  2. 计算机专业独显好还是集显好,集成显卡和独立显卡有什么区别?哪个性能更好?...

    电脑的硬件非常多,比如:主板.硬盘.显卡.鼠标等,不少用户买电脑的时候都会考虑到这些硬件,所以今天小编特意挑出一个硬件来讲,那就是显卡,显卡又分为两类,一个是集成显卡,一个是独立显卡,那么集成显卡和独 ...

  3. spyder pyecharts不显示_逆袭的IGZO-IPS小金刚!微星PAG272QRZ显示器评测:色域、响应速度更优秀...

    一.前言:小金刚市场再添新选手 IGZO-IPS来了 过去几年,各大厂商围绕着27寸2K高刷新率IPS面板这一标准,推出了大量"小金刚"规格的电竞显示器.同时,群创.友达和LGD这 ...

  4. python效率numpy_Python数据处理性能对比,原生,Pandas,Numpy哪个更优秀

    原标题:Python数据处理性能对比,原生,Pandas,Numpy哪个更优秀 今天为大家分享一个关于数据处理性能的对比,从原生,Pandas ,Numpy这三个方面对比?你觉得哪个更优秀呢?对于一个 ...

  5. Python数据处理性能对比,原生,Pandas,Numpy哪个更优秀

    https://blog.csdn.net/sinat_38682860/article/details/85765308 今天为大家分享一个关于数据处理性能的对比,从原生,Pandas ,Numpy ...

  6. 哈佛计算机系小哥哥中文字幕,【哈佛学霸小哥哥的一天】同样的24小时,为什么他们更优秀...

    原标题:[哈佛学霸小哥哥的一天]同样的24小时,为什么他们更优秀 暑假过半, 不知道放假之初, 那些雄心勃勃的暑期计划完成了多少呢? "我家孩子写作业慢,暑假过半,作业本还没打开!" ...

  7. 提高ADO性能的优秀经验

    一.概述 "性能"这一术语有着几种不同的.差异微妙的含义.当人们谈到某个东西性能多少好时,他们想要表达的意思可能就是在一定的时间之内它完成了多少工作.例如,一个性能好的发动机运行起 ...

  8. [美文]你懂得这些,才可能比别人更优秀!

    你懂得这些,才可能比别人更优秀! 自2020年以来由于疫情的影响,大批量的公司破产倒闭,即使能坚持下来的,也是推出了很多财务削减和人员裁减计划(美其名曰: 人员优化),这导致了大量各行各业人员的失业, ...

  9. mPaaS:全新移动开发平台,只为打造性能更优越的App

    简介: 基于移动开发现状与技术演进预判,提供移动开发强力解决方案,洞察 mPaaS 如何帮助企业有效降低技术门槛,减少研发成本,搭建更稳定.更流畅的移动 App. mPaaS 是源自于支付宝的移动开发 ...

最新文章

  1. python爬虫自学笔记分析解密_python爬虫学习笔记——1 各种文本分析工具简介之汇总...
  2. windows下挂载ext4_WSL2 支持挂载物理磁盘,Windows 可直接访问 ext4
  3. C++的高效从何而来
  4. 利用云计算打造政务信息化及应急指挥云平台
  5. git重命名远程仓库名字 同步fork代码
  6. java中HashSet对象内的元素的hashCode值不能变化
  7. Kali Linux Network Scanning Cookbook读书笔记之nmap
  8. jquery ajax和servlet,浅谈ajax在jquery中的请求和servlet中的响应
  9. 用c#算成绩的总和_用c#编写输出成绩的总分和平均分
  10. Rust: codewars的Roman Numerals Encoder
  11. java游戏2333整合包,3dm游戏运行库合集离线安装包
  12. 【计算机系统基础】- 袁春风
  13. 无线网络的暴力破解密码
  14. 高斯过程回归(GPR)
  15. Windows 2000 安全检查清单( 摘自《网络与安全》)
  16. 蓝色学校网站模板_中小学网站源码_学校网站管理系统
  17. android blowfish加密算法,blowfish 现在哪种加密算法安全?A
  18. Java 发送邮件的几种方式
  19. 中国医疗器械行业需求态势及未来前景趋势预测报告(2022-2027年)
  20. Java生成二维码图片,手机软件扫码后跳转网页

热门文章

  1. zbb20180710 maven Failed to read artifact descriptor--maven
  2. 62、滑动窗口的最大值
  3. iOS duplicate symbol for architecture arm64 解决办法
  4. C#集合类型——Array、ArrayList、List 之浅谈
  5. 6 四大组件之Service
  6. android 系统之ContentProvider
  7. 使用PowerShell配置Microsoft Teams
  8. nest 架构_当有人打来您的Nest Hello时,如何让Google Home通知您
  9. php获取一个文件名的函数,PHP 文件系统函数之获取文件名及文件名后缀-php文件...
  10. Android 干货,强烈推荐