国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

.NET Core/Framework如何創建委托大幅度提高反射調用的性能詳解

來源:懂視網 責編:小采 時間:2020-11-27 22:34:53
文檔

.NET Core/Framework如何創建委托大幅度提高反射調用的性能詳解

.NET Core/Framework如何創建委托大幅度提高反射調用的性能詳解:前言 大家都知道反射傷性能,但不得不反射的時候又怎么辦呢?當真的被問題逼迫的時候還是能找到解決辦法的。 反射是一種很重要的技術,然而它與直接調用相比性能要慢很多,因此如何優化反射性能也就成為一個不得不面對的問題。 目前最常見的優化反射性能的方
推薦度:
導讀.NET Core/Framework如何創建委托大幅度提高反射調用的性能詳解:前言 大家都知道反射傷性能,但不得不反射的時候又怎么辦呢?當真的被問題逼迫的時候還是能找到解決辦法的。 反射是一種很重要的技術,然而它與直接調用相比性能要慢很多,因此如何優化反射性能也就成為一個不得不面對的問題。 目前最常見的優化反射性能的方

前言

大家都知道反射傷性能,但不得不反射的時候又怎么辦呢?當真的被問題逼迫的時候還是能找到解決辦法的。

反射是一種很重要的技術,然而它與直接調用相比性能要慢很多,因此如何優化反射性能也就成為一個不得不面對的問題。 目前最常見的優化反射性能的方法就是采用委托:用委托的方式調用需要反射調用的方法(或者屬性、字段)。

為反射得到的方法創建一個委托,此后調用此委托將能夠提高近乎直接調用方法本身的性能。(當然 Emit 也能夠幫助我們顯著提升性能,不過直接得到可以調用的委托不是更加方便嗎?)

性能對比數據


▲ 沒有什么能夠比數據更有說服力(注意后面兩行是有秒數的)

可能我還需要解釋一下那五行數據的含義:

  1. 直接調用(😏應該沒有什么比直接調用函數本身更有性能優勢的吧)
  2. 做一個跟直接調用的方法功能一模一樣的委托(😮目的是看看調用委托相比調用方法本身是否有性能損失,從數據上看,損失非常小)
  3. 本文重點 將反射出來的方法創建一個委托,然后調用這個委托(🤩看看吧,性能跟直接調差別也不大嘛)
  4. 先反射得到方法,然后一直調用這個方法(😥終于可以看出來反射本身還是挺傷性能的了,50 多倍的性能損失啊)
  5. 緩存都不用,從頭開始反射然后調用得到的方法(😒100 多倍的性能損失了)

以下是測試代碼,可以更好地理解上圖數據的含義:

using System;
using System.Diagnostics;
using System.Reflection;

namespace Walterlv.Demo
{
 public class Program
 {
 static void Main(string[] args)
 {
 // 調用的目標實例。
 var instance = new StubClass();

 // 使用反射找到的方法。
 var method = typeof(StubClass).GetMethod(nameof(StubClass.Test), new[] { typeof(int) });
 Assert.IsNotNull(method);

 // 將反射找到的方法創建一個委托。
 var func = InstanceMethodBuilder<int, int>.CreateInstanceMethod(instance, method);

 // 跟被測方法功能一樣的純委托。
 Func<int, int> pureFunc = value => value;

 // 測試次數。
 var count = 10000000;

 // 直接調用。
 var watch = new Stopwatch();
 watch.Start();
 for (var i = 0; i < count; i++)
 {
 var result = instance.Test(5);
 }

 watch.Stop();
 Console.WriteLine($"{watch.Elapsed} - {count} 次 - 直接調用");

 // 使用同樣功能的 Func 調用。
 watch.Restart();
 for (var i = 0; i < count; i++)
 {
 var result = pureFunc(5);
 }

 watch.Stop();
 Console.WriteLine($"{watch.Elapsed} - {count} 次 - 使用同樣功能的 Func 調用");

 // 使用反射創建出來的委托調用。
 watch.Restart();
 for (var i = 0; i < count; i++)
 {
 var result = func(5);
 }

 watch.Stop();
 Console.WriteLine($"{watch.Elapsed} - {count} 次 - 使用反射創建出來的委托調用");

 // 使用反射得到的方法緩存調用。
 watch.Restart();
 for (var i = 0; i < count; i++)
 {
 var result = method.Invoke(instance, new object[] { 5 });
 }

 watch.Stop();
 Console.WriteLine($"{watch.Elapsed} - {count} 次 - 使用反射得到的方法緩存調用");

 // 直接使用反射調用。
 watch.Restart();
 for (var i = 0; i < count; i++)
 {
 var result = typeof(StubClass).GetMethod(nameof(StubClass.Test), new[] { typeof(int) })
 ?.Invoke(instance, new object[] { 5 });
 }

 watch.Stop();
 Console.WriteLine($"{watch.Elapsed} - {count} 次 - 直接使用反射調用");
 }

 private class StubClass
 {
 public int Test(int i)
 {
 return i;
 }
 }
 }
}

如何實現

實現的關鍵就在于 MethodInfo.CreateDelegate 方法。這是 .NET Standard 中就有的方法,這意味著 .NET Framework 和 .NET Core 中都可以使用。

此方法有兩個重載:

  • 要求傳入一個類型,而這個類型就是應該轉成的委托的類型
  • 要求傳入一個類型和一個實例,一樣的,類型是應該轉成的委托的類型
  • 他們的區別在于前者創建出來的委托是直接調用那個實例方法本身,后者則更原始一些,真正調用的時候還需要傳入一個實例對象。

    拿上面的 StubClass 來說明會更直觀一些:

    private class StubClass
    {
     public int Test(int i)
     {
     return i;
     }
    }

    前者得到的委托相當于 int Test(int i) 方法,后者得到的委托相當于 int Test(StubClass instance, int i) 方法。(在 IL 里實例的方法其實都是后者,而前者更像 C# 中的代碼,容易理解。)

    單獨使用 CreateDelegate 方法可能每次都需要嘗試第一個參數到底應該傳入些什么,于是我將其封裝成了泛型版本,增加易用性。

    using System;
    using System.Linq;
    using System.Reflection;
    using System.Diagnostics.Contracts;
    
    namespace Walterlv.Demo
    {
     public static class InstanceMethodBuilder<T, TReturnValue>
     {
     /// <summary>
     /// 調用時就像 var result = func(t)。
     /// </summary>
     [Pure]
     public static Func<T, TReturnValue> CreateInstanceMethod<TInstanceType>(TInstanceType instance, MethodInfo method)
     {
     if (instance == null) throw new ArgumentNullException(nameof(instance));
     if (method == null) throw new ArgumentNullException(nameof(method));
    
     return (Func<T, TReturnValue>) method.CreateDelegate(typeof(Func<T, TReturnValue>), instance);
     }
    
     /// <summary>
     /// 調用時就像 var result = func(this, t)。
     /// </summary>
     [Pure]
     public static Func<TInstanceType, T, TReturnValue> CreateMethod<TInstanceType>(MethodInfo method)
     {
     if (method == null)
     throw new ArgumentNullException(nameof(method));
    
     return (Func<TInstanceType, T, TReturnValue>) method.CreateDelegate(typeof(Func<TInstanceType, T, TReturnValue>));
     }
     }
    }

    泛型的多參數版本可以使用泛型類型生成器生成,我在 生成代碼,從 <T> 到 <T1, T2, Tn> —— 自動生成多個類型的泛型 - 呂毅 一文中寫了一個泛型生成器,可以稍加修改以便適應這種泛型類。

    總結

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    .NET Core/Framework如何創建委托大幅度提高反射調用的性能詳解

    .NET Core/Framework如何創建委托大幅度提高反射調用的性能詳解:前言 大家都知道反射傷性能,但不得不反射的時候又怎么辦呢?當真的被問題逼迫的時候還是能找到解決辦法的。 反射是一種很重要的技術,然而它與直接調用相比性能要慢很多,因此如何優化反射性能也就成為一個不得不面對的問題。 目前最常見的優化反射性能的方
    推薦度:
    標簽: 委托 net 性能
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 久久久无码精品亚洲日韩按摩 | 国产在线视频专区 | 91日韩| 亚洲欧美精品伊人久久 | 国产精品精品视频 | 欧美一区二区三区香蕉视 | 亚洲欧美日韩中文无线码 | 国内精品久久久久影院不卡 | 极品国产高颜值露脸在线 | 亚洲欧美日韩第一页 | 九一毛片 | 成人三级在线观看 | 国内精品久久久久 | 亚洲女人在线 | 国产亚洲一区二区精品 | 国产边打电话边做对白刺激 | 一级毛片免费下载 | 91亚洲国产系列精品第56页 | 精品日韩一区二区 | 91在线免费看 | 国产成人精品久久 | 美日韩在线视频 | 亚洲国产成人精彩精品 | 亚洲一区二区三区精品影院 | 欧美日在线观看 | 久久一次 | 亚洲一页| 国产精品久久久久久久久久免费 | 精品欧美日韩一区二区三区 | 国产综合精品久久久久成人影 | 国产欧美在线视频免费 | 一区二区三区视频在线播放 | 国产精品一区二区综合 | 手机在线观看国产精选免费 | 伊人色综合一区二区三区 | 精品一区二区三区免费视频 | 欧美午夜视频在线观看 | 色老头久久久久久久久久 | 色 在线播放 | 2020年国产高中毛片在线视频 | 欧美成人禁片在线www |