前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >寻找性能更优秀的动态 Getter 和 Setter 方案

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

原创
作者头像
newbe36524
修改2020-11-09 10:42:24
4770
修改2020-11-09 10:42:24
举报

反射获取 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
Getter
Setter
Setter

数据

Getter

Method

Job

Runtime

Mean

Error

StdDev

Median

Ratio

RatioSD

Rank

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

Method

Job

Runtime

Mean

Error

StdDev

Median

Ratio

RatioSD

Rank

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
Newbe.ObjectVisitor

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 方案说明
  • 知识要点
  • 实现代码
  • 基准测试
    • 结论
      • 图表
        • 数据
        • 总结
        • 我只是知识的搬运工
        • 发布说明
        • 使用样例
        • 番外分享
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档