寻找性能更优秀的不可变小字典

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

数据

MethodJobRuntimeMeanErrorStdDevRatioRatioSDRank
Directlynet461.NET 4.6.10.9347 ns0.0363 ns0.0321 ns1.000.001
ArrayIndexnet461.NET 4.6.115.0904 ns0.3820 ns0.3752 ns16.130.642
SwitchExpnet461.NET 4.6.117.1585 ns0.0624 ns0.0521 ns18.300.563
Dicnet461.NET 4.6.134.3348 ns0.2447 ns0.2169 ns36.771.184









Directlynet48.NET 4.80.6338 ns0.0233 ns0.0218 ns1.000.001
ArrayIndexnet48.NET 4.815.3098 ns0.2794 ns0.2613 ns24.170.692
SwitchExpnet48.NET 4.817.8113 ns0.0740 ns0.0656 ns28.200.983
Dicnet48.NET 4.833.7930 ns0.4538 ns0.4245 ns53.361.644









Directlynetcoreapp21.NET Core 2.11.2153 ns0.1168 ns0.1434 ns1.000.001
ArrayIndexnetcoreapp21.NET Core 2.14.6545 ns0.1044 ns0.0871 ns4.010.512
SwitchExpnetcoreapp21.NET Core 2.18.1995 ns0.2567 ns0.2747 ns6.810.903
Dicnetcoreapp21.NET Core 2.124.2669 ns0.5440 ns0.5586 ns20.072.514









Directlynetcoreapp31.NET Core 3.10.7382 ns0.1148 ns0.1074 ns1.000.001
ArrayIndexnetcoreapp31.NET Core 3.14.3580 ns0.1299 ns0.1085 ns6.100.772
SwitchExpnetcoreapp31.NET Core 3.17.5985 ns0.1310 ns0.1161 ns10.451.413
Dicnetcoreapp31.NET Core 3.122.2433 ns0.2756 ns0.2443 ns30.614.204









Directlynetcoreapp5.NET Core 5.01.3323 ns0.0527 ns0.0493 ns1.000.001
ArrayIndexnetcoreapp5.NET Core 5.05.0058 ns0.1361 ns0.1206 ns3.770.152
SwitchExpnetcoreapp5.NET Core 5.09.0576 ns0.0985 ns0.0921 ns6.810.263
Dicnetcoreapp5.NET Core 5.020.4052 ns0.2724 ns0.2275 ns15.440.594

总结

不论是数组跳表还是表达式 Switch 方案都可以解决这个问题,而且都要比使用字典要快。

但是这里有一个问题,就是目前作者还没有找到任何有关 MetadataToken 是否真的具备同 class 连续的性质。

因此建议还是使用 Switch 方案实现。

我只是知识的搬运工

- [Working with Expression Trees in C#](https://tyrrrz.me/blog/expression-trees)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307023.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一款基于.NET Core的认证授权解决方案-葫芦藤1.0开源啦

背景18年公司准备在技术上进行转型&#xff0c;而公司技术团队是互相独立的&#xff0c;新技术的推动阻力很大。我们需要找到一个切入点。公司的项目很多&#xff0c;而各个系统之间又不互通&#xff0c;导致每套系统都有一套登录体系&#xff0c;给员工和客户都带来极大的不便…

.NET架构小技巧(8)——优待异常

天有不测风云&#xff0c;人有旦夕祸福&#xff0c;程序呢——会有异常错误。C#中用try&#xff0c;catch&#xff0c;finally来捕捉处理异常&#xff0c;捕捉谁的异常呢&#xff1f;一般都是系统类库或三方类库中抛出的异常&#xff0c;那如果我自己架构程序&#xff0c;异常也…

跟我一起学.NetCore之EF Core 实战入门,一看就会

前言还记得当初学习数据库操作时&#xff0c;用ADO.NET一步一步地进行数据操作及查询&#xff0c;对于查询到的数据还得对其进行解析&#xff0c;然后封装返回给应用层&#xff1b;遇到这种重复而繁琐的工作&#xff0c;总有一些大神或团队对其进行封装&#xff0c;从而出现了很…

java 声明变量构成_Java—变量

1.1 按数据类型分类1.1.1 基本数据类型(四类八种)☛ 引用数据类型的特点存的是地址值,可以为null值☛ 基本数据类型的特点存的是具体的值,不可以是null值☛ 整型整型取值范围字节数byte(字节)-128 ~ 1271byteshort(短整型)-2byteint(默认整型)-4bytelong(长整型)12345678L8byte…

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

反射获取 PropertyInfo 可以对对象的属性值进行读取或者写入&#xff0c;但是这样性能不好。所以&#xff0c;我们需要更快的方案。方案说明 就是用表达式编译一个Action<TObj,TValue>作为 Setter&#xff0c;编译一个Func<TObj,TValue>作为 Getter。然后把这些编译…

Newbe.ObjectVisitor 0.2.10 发布,更花里胡哨

更新内容 现在&#xff0c;你可以通过上下文修改属性的值了&#xff1a;//✔️ from 0.2 // 可以修改属性 o.V().ForEach((context) > ModifyData(context)).Run();public static void ModifyData(IObjectVisitorContext<Yueluo,string> context) {context.Value con…

.NET 5 和 C#9 /F#5 一起到来, 向实现 .NET 统一迈出了一大步

经过一年多的开发&#xff0c;Microsoft 于北京时间 11 月 11 日&#xff08;星期三&#xff09;发布了其 .NET 5软件开发平台&#xff0c;强调平台的统一&#xff0c;并引入了 C# 9 和 F# 5 编程语言&#xff0c;新平台朝着桌面、Web、移动、云和 IoT 目标统一 .NET 开发体验的…

.NetCore HttpClient发送请求的时候为什么自动带上了一个RequestId头部?

奇怪的问题最近在公司有个系统需要调用第三方的一个webservice。本来调用一个下很简单的事情&#xff0c;使用HttpClient构造一个SOAP请求发送出去拿到XML解析就是了。可奇怪的是我们的请求在运行一段时间后就会被服务器504给拒绝掉了。导致系统无法使用&#xff0c;用户叫苦连…

ASP.NETCore小技巧:使用测试用户中间件

哈喽大家好&#xff0c;这篇文章其实很早就想写了&#xff0c;因为一直会有小伙伴问到&#xff0c;但是我却始终拿不到好的方案&#xff0c;最近在录制《eShopOnContainer微服务架构》的视频&#xff0c;碰巧就看到了微软官方的代码中也有这方面的需求&#xff0c;而且和我的需…

【招聘(深圳)】华强方特文化科技集团 .NET工程师

.NET高级开发工程师&#xff08;18-25K&#xff09;岗位职责&#xff1a;负责系统需求分析与设计&#xff1b;根据业务确定实现方案&#xff1b;对现有系统缺陷提出优化方案&#xff1b;负责系统关键功能开发及维护&#xff0c;保障系统的正常运行&#xff1b;带领指导团队开发…

11座城市,58个.NET最新岗位速览,内推直通面试官!

十一月风雪客&#xff0c;十二月乘衣归&#xff01;各个大厂秋招进行时&#xff0c;你行动了吗&#xff1f;借着这阵风&#xff0c;今天为大家提供一批.NET开发岗位内推&#xff01;58个优质的.NET开发岗位年薪过万到百万不等&#xff0c;总有一个适合你&#xff01;包含全国各…

pdo mysql_PDO MySQL

PDO MySQL如果文章有成千上万篇&#xff0c;该怎样保存&#xff1f;数据保存有多种方式&#xff0c;比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择&#xff0c;做Web一般采用MySQL&#xff0c;本书也以MySQL为例。自学&#xff1a;1天。假…

C# 8: 可变结构体中的只读实例成员

在之前的文章中我们介绍了 C# 中的 只读结构体&#xff08;readonly struct&#xff09;[1] 和与其紧密相关的 in 参数[2]。今天我们来讨论一下从 C# 8 开始引入的一个特性&#xff1a;可变结构体中的只读实例成员&#xff08;当结构体可变时&#xff0c;将不会改变结构体状态的…

部署Dotnet Core应用到Kubernetes(一)

最近闲了点&#xff0c;写个大活&#xff1a;部署Dotnet应用到K8s。写在前边的话一直想完成这个主题。但这个主题实在太大了&#xff0c;各种拖延症的小宇宙不时爆发一下&#xff0c;结果就拖到了现在。这个主题&#xff0c;会是一个系列。在这个系列中&#xff0c;我会讨论将应…

JAVA实验报告九异常处理_Java课后练习9(异常处理)

动手动脑1:import javax.swing.*;class AboutException {public static void main(String[] a){int i1, j0, k;ki/j;try{k i/j; // Causes division-by-zero exception//throw new Exception("Hello.Exception!");}catch ( ArithmeticException e){System.out.print…

java 实现 指派_TAP任务指派问题的汇编实现

近六周的课程设计&#xff0c;编了一个四百行的汇编程序&#xff0c;编的过程很不顺利&#xff0c;遇到种种意想不到的困难&#xff0c;但最终能够实现&#xff0c;可谓欣喜若狂&#xff0c;这期间学到了好多好多&#xff0c;遇到问题怎么精下心来解决&#xff0c;同时对汇编的…

.NET 5.0正式发布,有什么功能特性(翻译)

我们很高兴今天.NET5.0正式发布。这是一个重要的版本—其中也包括了C# 9和F# 5大量新特性和优秀的改进。微软和其他公司的团队已经在生产和性能测试环境中开始使用了。这些团队向我们反馈的结果比较令人满意&#xff0c;它证明了对性能提升及降低Web应用托管成本的机会有积极的…

简单聊聊C#中lock关键字

为了避免多个线程同时操作同一资源&#xff0c;引起数据错误&#xff0c;通常我们会将这个资源加上锁&#xff0c;这样在同一时间只能有一个线程操作资源。在C#中我们使用lock关键字来锁定资源&#xff0c;那lock关键字是如何实现锁定的呢&#xff1f;我们先看一段代码&#xf…

idea如何导入java工程_Eclipse java web项目 ,导入IntelliJ IDEA 完整操作!

或许你用惯了Eclipse&#xff0c;有点排斥其他工具了&#xff0c;你写框架的时候&#xff0c;编译速度是不是特别慢啊&#xff1f;有时候还超过45秒&#xff0c;自动取消运行&#xff01;有时候代码是正常的&#xff0c;却无端端报错&#xff1f;下午吃个饭回来又好了&#xff…

行业思考 | 互联网对传统行业的降维打击

【行业思考】| 作者 / Edison Zhou这是EdisonTalk的第301篇原创内容在周一发布的推文《我在传统行业做数字化转型之预告篇》中&#xff0c;我提到互联网的发展和和竞争对传统行业起到了降维打击的作用&#xff0c;于是就有童鞋私下问我&#xff0c;为何这么说。今天就跟你聊聊这…