反射這玩意,一直以來都是慢的代名詞 。一說XXX系統大量的反射,好多人第一印象就是會慢 。
但是呢,我們又不得不使用反射來做一些事情,畢竟這玩意可以說啥都能干了對吧 。
It’s immensely powerful, providing the ability to query all of the metadata for code in your process and for arbitrary assemblies you might encounter, to invoke arbitrary functionality dynamically, and even to emit dynamically-generated IL at run-time.當然.Net也提供了一些性能更高的方法 。
比如
SG,這玩意是性能最好的方案,它在編譯的時候生成代碼,運行的時候一點反射沒有,同時也完美支持Native AOT 。但是呢,它還不是真正的動態生成,只能說是開發時動態 。所以更適合一些框架程序使用來提高執行效率 。還有比如
Emit,這玩意是動態編織IL代碼的,效率也比反射要快 。但是呢,寫起來極度復雜,10個人有8個都撓頭 。所以,.Net 7里反射還是非常重要的一部分,也針對它做了一些比較牛逼的優化 。
- 我們知道,給
MethodBase使用CreateDelegate<T>來創建一個委托,然后調用這個委托是最佳方法 。但是呢,我們編譯的時候經常是不知道這個方法簽名的,也就是沒法生成這個委托 。部分庫已經使用Emit來生成代碼提高速度了 。但是我們普通用戶顯然區寫一堆Emit是不現實的 。.Net 7優化后,會把我們的反射代碼優化為DynamicMethod形式的委托,然后調用 。
我們來看一下數據
private MethodInfo _method;[GlobalSetup]public void Setup() => _method = typeof(Program).GetMethod("MyMethod", BindingFlags.NonPublic | BindingFlags.Static);[Benchmark]public void MethodInfoInvoke() => _method.Invoke(null, null);private static void MyMethod() { }MethodRuntime
Mean
Ratio
MethodInfoInvoke
.NET 6.0
43.846 ns
1.00
MethodInfoInvoke
.NET 7.0
8.078 ns
0.18
我們可以看到,這玩意速度提升了好幾倍 。
反射還有一個用處就是對類型、方法、屬性等等這些東西進行獲取 。一些其他的改進也會影響到這一部分 。比如.Net最近一直在做的把原生類型轉換為托管類型的工作,就產生了這么一個東西 。
[Benchmark]public Type GetUnderlyingType() => Enum.GetUnderlyingType(typeof(DayOfWeek));MethodRuntime
Mean
Ratio
GetUnderlyingType
.NET 6.0
27.413 ns
1.00
GetUnderlyingType
.NET 7.0
5.115 ns
0.19
是的,原生類型轉換為托管類型,不但沒有拖慢反射,反而讓它快了好幾倍 。
同樣的例子,有大量的
AssemblyName的內容從原生轉向了CoreLib,所以Activator.CreateInstance也跟著變快了 。private readonly string _assemblyName = typeof(MyClass).Assembly.FullName;private readonly string _typeName = typeof(MyClass).FullName;public class MyClass { }[Benchmark]public object CreateInstance() => Activator.CreateInstance(_assemblyName, _typeName);MethodRuntime
Mean
Ratio
CreateInstance
.NET 6.0
3.827 us
1.00
CreateInstance
.NET 7.0
2.276 us
0.60
這玩意雖然沒有那么夸張,但是提升可以說也是不小了 。
RuntimeType.CreateInstanceImpl現在使用Type.EmptyTypes代替了new Type[0],所以節省了一部分開銷 。[Benchmark]public void CreateInstance() => Activator.CreateInstance(typeof(MyClass), BindingFlags.NonPublic | BindingFlags.Instance, null, Array.Empty<object>(), null);internal class MyClass{internal MyClass() { }}
經驗總結擴展閱讀
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 西游記的主要內容
- 童年的主要內容
- 教師個人讀書計劃內容
- winget 使用 Windows 包管理器 安裝 .Net
- 有趣實驗 .NET下數據庫的負載均衡
- 傅雷家書主要內容
- 無悔華夏11月11日漁樵問答內容
- 魯濱遜漂流記的主要內容講的是啥
- 城南舊事主要內容
- 防溺水手抄報的內容怎么寫
