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


    反射获取 PropertyInfo 可以对对象的属性值进行读取或者写入,但是这样性能不好。所以,我们需要更快的方案。

    方案说明

    就是用表达式编译一个 Action<TObj,TValue> 作为 Setter,编译一个 Func<TObj,TValue> 作为 Getter。

    然后把这些编译好的委托放在一个泛型类的静态字段中保存起来,需要使用的时候从这里面查找就可以了。

    知识要点

    1. 使用表达式创建委托
    2. 泛型类的静态字段是每个闭合类型独立的,因此用于存储和类型相关的内容非常方便

    实现代码

    由于代码中混合的使用 Switch 作为字典的阴招,所以代码很长,此处不再罗列,仅给出链接:

    基准测试

    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 RyuJIT
      net461       : .NET Framework 4.8 (4.8.4250.0), X64 RyuJIT
      net48        : .NET Framework 4.8 (4.8.4250.0), X64 RyuJIT
      netcoreapp21 : .NET Core 2.1.23 (CoreCLR 4.6.29321.03, CoreFX 4.6.29321.01), X64 RyuJIT
      netcoreapp31 : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
      netcoreapp5  : .NET Core 5.0.0 (CoreCLR 5.0.20.47505, CoreFX 5.0.20.47505), X64 RyuJIT

    结论

    1. 使用委托明显比使用 PropertyInfo 要快,这个方案可以。
    2. Framework 真拉胯,Net 5 简直太强了。
    3. 如果属性是明确的,建议把字典中取出来的委托保存在自己的上下文,这可以明显的省去查找的消耗。

    图表

    从左往右分别是:直接读取属性、缓存委托、不缓存委托和使用 PropertyInfo。

    Getter
    Setter

    数据

    Getter

    MethodJobRuntimeMeanErrorStdDevMedianRatioRatioSDRank
    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

    MethodJobRuntimeMeanErrorStdDevMedianRatioRatioSDRank
    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。

    我只是知识的搬运工

    发布说明

    使用样例

    番外分享

    GitHub 项目地址:https://github.com/newbe36524/Newbe.ObjectVisitor

    Gitee 项目地址:https://gitee.com/yks/Newbe.ObjectVisitor

    Newbe.ObjectVisitor

    ************转摘:https://www.cnblogs.com/newbe36524/p/13946267.html

  • 相关阅读:
    redis-client和redis-template存储的key的格式不一样
    dubbo+zookeeper基础
    java面试题1
    Spring线程池(异步、同步)
    Java并发多线程
    Java并发-并发工具类JUC
    Java并发面试题
    ActiveMQ
    一键部署springboot到Docker
    Quartz任务调度学习
  • 原文地址:https://www.cnblogs.com/linybo/p/13947267.html
Copyright © 2020-2023  润新知