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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET Core/Framework 创建委托以大幅度提高反射调用的性能

發(fā)布時(shí)間:2023/12/4 asp.net 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET Core/Framework 创建委托以大幅度提高反射调用的性能 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

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


性能對比數(shù)據(jù)


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

可能我還需要解釋一下那五行數(shù)據(jù)的含義:

  • 直接調(diào)用(?應(yīng)該沒有什么比直接調(diào)用函數(shù)本身更有性能優(yōu)勢的吧)

  • 做一個(gè)跟直接調(diào)用的方法功能一模一樣的委托(?目的是看看調(diào)用委托相比調(diào)用方法本身是否有性能損失,從數(shù)據(jù)上看,損失非常小)

  • 本文重點(diǎn)?將反射出來的方法創(chuàng)建一個(gè)委托,然后調(diào)用這個(gè)委托(?看看吧,性能跟直接調(diào)差別也不大嘛)

  • 先反射得到方法,然后一直調(diào)用這個(gè)方法(?終于可以看出來反射本身還是挺傷性能的了,50 多倍的性能損失啊)

  • 緩存都不用,從頭開始反射然后調(diào)用得到的方法(?100 多倍的性能損失了)

  • 以下是測試代碼,可以更好地理解上圖數(shù)據(jù)的含義:

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

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

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

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

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

    ????????????//?測試次數(shù)。
    var count = 10000000;

    ????????????//?直接調(diào)用。
    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} 次 - 直接調(diào)用");

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

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

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

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

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

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

    ????????????//?直接使用反射調(diào)用。
    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} 次 - 直接使用反射調(diào)用");
    }

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

    上面的代碼中,有一個(gè)我們還沒有實(shí)現(xiàn)的?InstanceMethodBuilder?類型,接下來將介紹如何實(shí)現(xiàn)它。

    如何實(shí)現(xiàn)

    實(shí)現(xiàn)的關(guān)鍵就在于?MethodInfo.CreateDelegate?方法。這是?.NET?Standard?中就有的方法,這意味著?.NET?Framework?和?.NET?Core?中都可以使用。

    此方法有兩個(gè)重載:

    • 要求傳入一個(gè)類型,而這個(gè)類型就是應(yīng)該轉(zhuǎn)成的委托的類型

    • 要求傳入一個(gè)類型和一個(gè)實(shí)例,一樣的,類型是應(yīng)該轉(zhuǎn)成的委托的類型

    他們的區(qū)別在于前者創(chuàng)建出來的委托是直接調(diào)用那個(gè)實(shí)例方法本身,后者則更原始一些,真正調(diào)用的時(shí)候還需要傳入一個(gè)實(shí)例對象。

    拿上面的?StubClass?來說明會(huì)更直觀一些:

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

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

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

    using System;
    using System.Linq;
    using System.Reflection;
    using System.Diagnostics.Contracts;

    namespace Walterlv.Demo
    {
    public static class InstanceMethodBuilder<T, TReturnValue>
    {
    /// <summary>
    ????????///?調(diào)用時(shí)就像?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>
    ????????///?調(diào)用時(shí)就像?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>));
    }
    }
    }

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


    原文地址:https://blog.walterlv.com/post/create-delegate-to-improve-reflection-performance.html?

    .NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?


    總結(jié)

    以上是生活随笔為你收集整理的.NET Core/Framework 创建委托以大幅度提高反射调用的性能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。