日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/4 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 寻找性能更优秀的不可变小字典 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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 簡直太強了。

  • 數組跳表是非直接方案中最快的。

  • 圖表

    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)

    總結

    以上是生活随笔為你收集整理的寻找性能更优秀的不可变小字典的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。