反射 表達式樹 DLR 性能,效率 對比

從網上看到了各種反射與表達式樹的性能對比.於是自己也寫了代碼進行測試.發現循環10萬次以下時性能相差不大.





<%@ Page Language="C#" AutoEventWireup="true" CodeFile="反射表達式樹DLR性能對比.aspx.cs" Inherits="序列反射動態程式集_反射表達式樹DLR性能對比" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>反射表達式樹DLR性能對比</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
    </div>
    </form>
</body>
</html>







using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class 序列反射動態程式集_反射表達式樹DLR性能對比 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {


        //填充數據
        Action act = () => { InitTypePropertyAssignExpression<TestCalass>(true); };


        Response.Write("轉換完成:" + act.StopwatchRun() + "毫秒<br/>");


        List<double> lis = new List<double>() { 0.1,0.5, 10, 20, 30, 50,100,200 };

        //不同循環次數對比
        foreach (double num in lis)
        {

            RunDiff(num);
        }

    }


    #region 填充與計算方法

    Random dom = new Random();
    /// <summary>
    /// 開始比較方法
    /// </summary>
    /// <param name="num">進行多少次比較</param>
    public void RunDiff(double num = 10)
    {
        //10萬次計算時間對比
        var arr = System.Linq.Enumerable.Range(1, (int)(num * 10000)).ToList();

        TestCalass c = new TestCalass();

        Action 手動編碼 = () =>
        {
            arr.ForEach((o) =>
            {
                
                產生隨機值並且填充對像(c, 2);
            });
        };

        Action 表達式樹 = () =>
        {
            arr.ForEach((o) =>
            {
                //TestCalass c = new TestCalass();
                產生隨機值並且填充對像(c, 0);

            });
        };


        Action 反射 = () =>
        {
            arr.ForEach((o) =>
            {
               // TestCalass c = new TestCalass();
                產生隨機值並且填充對像(c, 1);
            });
        };

        long v0, v1, v2;

        Response.Write(string.Format("{0} 運行 {1} 萬次,用時{2}毫秒<br/>", "手動編碼", arr.Count / 10000.0, v2 = 手動編碼.StopwatchRun()));
        Response.Write(string.Format("{0} 運行 {1} 萬次,用時{2}毫秒<br/>", "表達式樹", arr.Count / 10000.0, v0 = 表達式樹.StopwatchRun()));
        Response.Write(string.Format("{0} 運行 {1} 萬次,用時{2}毫秒<br/>", "反射賦值", arr.Count / 10000.0, v1 = 反射.StopwatchRun()));
        Response.Write(string.Format("{0}爲基準值 {1}用時{2};   {3}用時{4}  相差:{5},快了{6}倍 ", v2, "表達式樹", v0-v2, "反射賦值", v1-v2, (v1 - v0),( v1-v0 )/(v0-v2) ));
        Response.Write(string.Format("--------------------------<br/>"));

    }

    /// <summary>
    /// 設置反射數據
    /// </summary>
    public void RefSetvalue(System.Reflection.PropertyInfo p, TestCalass t, object val)
    {
        p.SetValue(t, val, null);
    }

    public void 產生隨機值並且填充對像(TestCalass c, int isExpression = 1)
    {
        foreach (var p in exProinfoDic)
        {

            if (p.Value.PropertyType == typeof(int))
            {
                int val = dom.Next(1, int.MaxValue);
                //是否使用表達式賦值
                if (isExpression == 0)
                {
                    //傳值
                    p.Value.ActionAssign(val, c);
                    continue;
                }
                if (isExpression == 1)
                {
                    RefSetvalue(p.Value.PropertyInfo, c, val);
                    continue;
                }
                if (isExpression == 2)
                {
                    c.a = val;
                    continue;
                }
            }


            if (p.Value.PropertyType == typeof(string))
            {
                string val = Guid.NewGuid().ToString();
                //是否使用表達式賦值
                if (isExpression == 0)
                {
                    //傳值
                    p.Value.ActionAssign(val, c);
                    continue;
                }
                if (isExpression == 1)
                {
                    RefSetvalue(p.Value.PropertyInfo, c, val);
                    continue;
                }
                if (isExpression == 2)
                {
                    c.b = val;
                    continue;
                }
            }

            if (p.Value.PropertyType == typeof(DateTime))
            {
                int vald = dom.Next(1, int.MaxValue);
                DateTime val = DateTime.Now.AddMilliseconds(vald);
                //是否使用表達式賦值
                if (isExpression == 0)
                {
                    //傳值
                    p.Value.ActionAssign(val, c);
                    continue;
                }
                if (isExpression == 1)
                {
                    RefSetvalue(p.Value.PropertyInfo, c, val);
                    continue;
                }
                if (isExpression == 2)
                {
                    c.c = val;
                    continue;
                }
            }

            if (p.Value.PropertyType == typeof(double[]))
            {
                double[] val = new double[50];
                for (int i = 0; i < val.Length; i++)
                {
                    val[i] = dom.Next(1, int.MaxValue);
                }
                //是否使用表達式賦值
                if (isExpression == 0)
                {
                    //傳值
                    p.Value.ActionAssign(val, c);
                    continue;
                }
                if (isExpression == 1)
                {
                    RefSetvalue(p.Value.PropertyInfo, c, val);
                    continue;
                }
                if (isExpression == 2)
                {
                    c.Arr = val;
                    continue;
                }
            }

        }
    }

    #endregion



    /// <summary>
    /// 初始化類型屬性表達式操作,只能處理基元類型
    /// </summary>
    ///<exception cref="System.Collections.Generic.KeyNotFoundException">沒有找到合適的處理方法</exception>
    ///<param name="NotFindConvertObject">沒有找到合適類型自動轉換成爲object</param>
    public void InitTypePropertyAssignExpression<T>(bool NotFindConvertObject = false)
    {
        //初始化表達式
        foreach (var p in typeof(T).GetProperties())
        {
            //C# 所有基元類型
            if (CreateExpression<T, byte>(p)) { continue; }
            if (CreateExpression<T, sbyte>(p)) { continue; }
            if (CreateExpression<T, int>(p)) { continue; }
            if (CreateExpression<T, uint>(p)) { continue; }
            if (CreateExpression<T, short>(p)) { continue; }
            if (CreateExpression<T, ushort>(p)) { continue; }
            if (CreateExpression<T, long>(p)) { continue; }
            if (CreateExpression<T, ulong>(p)) { continue; }
            if (CreateExpression<T, float>(p)) { continue; }
            if (CreateExpression<T, double>(p)) { continue; }
            if (CreateExpression<T, char>(p)) { continue; }
            if (CreateExpression<T, bool>(p)) { continue; }
            if (CreateExpression<T, string>(p)) { continue; }
            if (CreateExpression<T, decimal>(p)) { continue; }
            if (CreateExpression<T, object>(p)) { continue; }
            if (CreateExpression<T, DateTime>(p)) { continue; }

            if (NotFindConvertObject)
            {
                //沒有找到合適的類型自動轉換成爲object
                CreateExpression<T, object>(p, true);
            }
            else
            {
                throw new KeyNotFoundException("沒有找到合適的基元類型");

            }
        }
    }

    /// <summary>
    /// 創建屬性表達式數據實體
    /// </summary>
    /// <typeparam name="T">類型</typeparam>
    /// <typeparam name="TValue">屬性的 值類型</typeparam>
    /// <param name="p">屬性信息</param>
    /// <param name="toObject">轉換成爲Object</param>
    /// <returns>成功返回true</returns>
    protected bool CreateExpression<T, TValue>(System.Reflection.PropertyInfo p, bool toObject = false)
    {

        if (p.PropertyType == typeof(TValue) || toObject)
        {
            //添加到緩存集合
            return exProinfoDic.TryAdd(p.Name, new ExpressionPropertyInfo()
             {
                 PropertyType = p.PropertyType,
                 PropertyName = p.Name,
                 PropertyInfo = p,
                 ActionAssign = GetExpression<T, TValue>(p.Name)
             });
        }



        return false;
    }

    /// <summary>
    /// 表達式類型屬性信息對像緩存
    /// </summary>
    System.Collections.Concurrent.ConcurrentDictionary<string, ExpressionPropertyInfo> exProinfoDic = new System.Collections.Concurrent.ConcurrentDictionary<string, ExpressionPropertyInfo>();


    /// <summary>
    /// 一個屬性傳值操作 表達式
    /// </summary>
    /// <param name="propertyName">屬性名</param>
    /// <typeparam name="T">實體類型值</typeparam>
    /// <typeparam name="TValue">屬性類型值</typeparam>
    /// <returns></returns>
    public Func<TValue, T, TValue> GetExpression<T, TValue>(string propertyName)
    {
        Type t = typeof(T);
        System.Reflection.PropertyInfo pro = t.GetProperty(propertyName);
        return GetExpression<T, TValue>(pro);
    }

    /// <summary>
    /// 一個屬性傳值操作 表達式
    /// </summary>
    /// <param name="propertyInfo">屬性對像</param>
    /// <typeparam name="T">實體類型值</typeparam>
    /// <typeparam name="TValue">屬性類型值</typeparam>
    /// <returns></returns>
    public Func<TValue, T, TValue> GetExpression<T, TValue>(System.Reflection.PropertyInfo propertyInfo)
    {
        Type t = typeof(T);
        Type vt = typeof(TValue);
        //參數p
        System.Linq.Expressions.ParameterExpression p = System.Linq.Expressions.Expression.Parameter(t, "p");
        //參數值 v
        System.Linq.Expressions.ParameterExpression v = System.Linq.Expressions.Expression.Parameter(vt, "v");

        //屬性 curp
        System.Linq.Expressions.MemberExpression curP = System.Linq.Expressions.Expression.Property(p, propertyInfo);


        //賦值操作
        System.Linq.Expressions.BinaryExpression ass = null;
        if (vt != propertyInfo.PropertyType)
        {
            //轉換表達式 v
            System.Linq.Expressions.UnaryExpression conv = System.Linq.Expressions.Expression.Convert(v, propertyInfo.PropertyType);
            //賦值操作
            ass = System.Linq.Expressions.Expression.Assign(curP, conv);

        }
        else
        {
            ass = System.Linq.Expressions.Expression.Assign(curP, v);
        }


        //表達式結果
        System.Linq.Expressions.Expression<Func<TValue, T, TValue>> result = System.Linq.Expressions.Expression.Lambda<Func<TValue, T, TValue>>(ass, v, p);

        //返回編譯後結果
        return result.Compile();

    }



    /// <summary>
    /// 表達式類型屬性信息對像
    /// </summary>
    public class ExpressionPropertyInfo
    {
        /// <summary>
        /// 屬性名
        /// </summary>
        public string PropertyName { get; set; }

        /// <summary>
        /// 屬性類型
        /// </summary>
        public Type PropertyType { get; set; }

        /// <summary>
        /// 屬性對像
        /// </summary>
        public System.Reflection.PropertyInfo PropertyInfo { get; set; }

        /// <summary>
        /// 賦值操作委託
        /// </summary>
        public dynamic ActionAssign { get; set; }

    }

    /// <summary>
    /// 測試用類
    /// </summary>
    public class TestCalass
    {
        public int a { get; set; }

        public string b { get; set; }

        public DateTime c { get; set; }

        public double[] Arr { get; set; }

    }
}


擴展方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace System
{
    /// <summary>
    /// 通用調試方法
    /// </summary>
    public static class TongTestExpand
    {

        /// <summary>
        /// 測試此方法運行時間
        /// </summary>
        /// <param name="act">運行方法</param>
        /// <returns>返回時間單位毫秒</returns>
        public static long StopwatchRun(this Action act)
        {
            System.Diagnostics.Stopwatch sa = new System.Diagnostics.Stopwatch();
            long result = 0;
            sa.Restart();

            try
            {
                act();
            }
            finally
            {

                sa.Stop();
                result = sa.ElapsedMilliseconds;
            }
            return result;
        }

    }
}


運行結果1(不需要每次創建值)

轉換完成:11毫秒
手動編碼 運行 0.1 萬次,用時7毫秒
表達式樹 運行 0.1 萬次,用時48毫秒
反射賦值 運行 0.1 萬次,用時6毫秒
7爲基準值 表達式樹用時41; 反射賦值用時-1 相差:-42,快了-1倍 
--------------------------
手動編碼 運行 0.5 萬次,用時18毫秒
表達式樹 運行 0.5 萬次,用時22毫秒
反射賦值 運行 0.5 萬次,用時33毫秒
18爲基準值 表達式樹用時4; 反射賦值用時15 相差:11,快了2倍 
--------------------------
手動編碼 運行 10 萬次,用時403毫秒
表達式樹 運行 10 萬次,用時445毫秒
反射賦值 運行 10 萬次,用時667毫秒
403爲基準值 表達式樹用時42; 反射賦值用時264 相差:222,快了5倍 
--------------------------
手動編碼 運行 20 萬次,用時784毫秒
表達式樹 運行 20 萬次,用時901毫秒
反射賦值 運行 20 萬次,用時1348毫秒
784爲基準值 表達式樹用時117; 反射賦值用時564 相差:447,快了3倍 
--------------------------
手動編碼 運行 30 萬次,用時1178毫秒
表達式樹 運行 30 萬次,用時1344毫秒
反射賦值 運行 30 萬次,用時2003毫秒
1178爲基準值 表達式樹用時166; 反射賦值用時825 相差:659,快了3倍 
--------------------------
手動編碼 運行 50 萬次,用時1987毫秒
表達式樹 運行 50 萬次,用時2285毫秒
反射賦值 運行 50 萬次,用時3396毫秒
1987爲基準值 表達式樹用時298; 反射賦值用時1409 相差:1111,快了3倍 
--------------------------
手動編碼 運行 100 萬次,用時4013毫秒
表達式樹 運行 100 萬次,用時4625毫秒
反射賦值 運行 100 萬次,用時6798毫秒
4013爲基準值 表達式樹用時612; 反射賦值用時2785 相差:2173,快了3倍 
--------------------------
手動編碼 運行 200 萬次,用時8277毫秒
表達式樹 運行 200 萬次,用時9281毫秒
反射賦值 運行 200 萬次,用時13773毫秒
8277爲基準值 表達式樹用時1004; 反射賦值用時5496 相差:4492,快了4倍 
--------------------------



運行效果2(在方法中每次創建值)

轉換完成:11毫秒
手動編碼 運行 0.1 萬次,用時7毫秒
表達式樹 運行 0.1 萬次,用時48毫秒
反射賦值 運行 0.1 萬次,用時6毫秒
7爲基準值 表達式樹用時41; 反射賦值用時-1 相差:-42,快了-1倍 
--------------------------
手動編碼 運行 0.5 萬次,用時18毫秒
表達式樹 運行 0.5 萬次,用時22毫秒
反射賦值 運行 0.5 萬次,用時33毫秒
18爲基準值 表達式樹用時4; 反射賦值用時15 相差:11,快了2倍 
--------------------------
手動編碼 運行 10 萬次,用時403毫秒
表達式樹 運行 10 萬次,用時445毫秒
反射賦值 運行 10 萬次,用時667毫秒
403爲基準值 表達式樹用時42; 反射賦值用時264 相差:222,快了5倍 
--------------------------
手動編碼 運行 20 萬次,用時784毫秒
表達式樹 運行 20 萬次,用時901毫秒
反射賦值 運行 20 萬次,用時1348毫秒
784爲基準值 表達式樹用時117; 反射賦值用時564 相差:447,快了3倍 
--------------------------
手動編碼 運行 30 萬次,用時1178毫秒
表達式樹 運行 30 萬次,用時1344毫秒
反射賦值 運行 30 萬次,用時2003毫秒
1178爲基準值 表達式樹用時166; 反射賦值用時825 相差:659,快了3倍 
--------------------------
手動編碼 運行 50 萬次,用時1987毫秒
表達式樹 運行 50 萬次,用時2285毫秒
反射賦值 運行 50 萬次,用時3396毫秒
1987爲基準值 表達式樹用時298; 反射賦值用時1409 相差:1111,快了3倍 
--------------------------
手動編碼 運行 100 萬次,用時4013毫秒
表達式樹 運行 100 萬次,用時4625毫秒
反射賦值 運行 100 萬次,用時6798毫秒
4013爲基準值 表達式樹用時612; 反射賦值用時2785 相差:2173,快了3倍 
--------------------------
手動編碼 運行 200 萬次,用時8277毫秒
表達式樹 運行 200 萬次,用時9281毫秒
反射賦值 運行 200 萬次,用時13773毫秒
8277爲基準值 表達式樹用時1004; 反射賦值用時5496 相差:4492,快了4倍 
--------------------------


和網上(所說的100倍有很大的區別)



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章