ASP.NET MVC - 漫谈ActionMethodDispatcher

跳过ASP.NET MVC中所有的路由映射和各种有的没的缓存机制,一个个请求从发送到处理,最终是由Action去执行的,而在ASP.NET MVC中,Action的最终执行者叫做ActionMethodDispacher。

在这篇文章中,我想从无到有地建立一个Dispatcher,顺便窥探一下ASP.NET MVC中Action的执行机制。

在没有看源码之前,我觉得这个Dispatcher没有什么了不起,不就是个动态函数调用嘛,使用反射调用不就就行了,几行代码随便搞定:

    public class ReflectionDispatcher
    {
        public MethodInfo MethodInfo {get;set;}

        public ReflectionDispatcher(MethodInfo methodInfo)
        {
            MethodInfo = methodInfo;
        }

        public object Execute(TestClass instance, object[] parameters)
        {
            return MethodInfo.Invoke(instance, parameters);
        }
    }

多么简单,简直就是一目了然,为了这么点功能,建一个类简直就是多余!

但是,如果ASP.NET MVC中的ActionMethodDispacher也是这样实现的话,那么...嘿嘿,估计会被人骂的很惨吧。

原因是这个ReflectDispacher的性能非常低下,不是因为代码写得太差,只是因为反射调用先天不足,本来就有性能的瓶颈。

关于如何高效动态调用函数,这里就不多说了,详见:http://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker

下面我试着仿照ASP.NET MVC的ActionMethodDispacher来建一个性能高点的Dispacher,至于性能可以高多少,不妨等下做个小试验。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;

namespace MvcConsole
{
    public class ActionMethodDispatcher
    {
        private delegate object ActionExecutor(TestClass instance, object[] parameters);
        private delegate void VoidActionExecutor(TestClass instance, object[] parameters);

        private ActionExecutor _executor;

        private static ActionExecutor BuildActionExecutor(MethodInfo method)
        {
            ParameterExpression instanceParameter = Expression.Parameter(typeof(TestClass), "instance");
            ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
            List<Expression> parameters = new List<Expression>();

            ParameterInfo[] parameterInfos = method.GetParameters();

            for (int i = 0; i < parameterInfos.Length; i++)
            {
                ParameterInfo paramInfo = parameterInfos[i];
                BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
                UnaryExpression valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);
                parameters.Add(valueCast);
            }

            MethodCallExpression methodCall = Expression.Call(instanceParameter, method, parameters);


            return
                methodCall.Type == typeof(void) ?
                WrapVoidAction(Expression.Lambda<VoidActionExecutor>(methodCall, instanceParameter, parametersParameter).Compile()) :
                Expression.Lambda<ActionExecutor>(methodCall, instanceParameter, parametersParameter).Compile();
        }

        public ActionMethodDispatcher(MethodInfo methodInfo)
        {
            _executor = BuildActionExecutor(methodInfo);
        }

        public object Execute(TestClass instance, object[] parameters)
        {
            return _executor(instance, parameters);
        }

        private static ActionExecutor WrapVoidAction(VoidActionExecutor executor)
        {
            return (instance, parameters) =>
            {
                executor(instance, parameters);
                return null;
            };
        }
    }
}

从这个代码中,我们明显可以看到,这个Dispacher貌似要“胖”很多。

下面就来比较下两个Dispatcher的性能:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;
using System.Diagnostics;

namespace MvcConsole
{
    public class TestClass
    {
        public String State { get; set; }

        public TestClass()
        {
            State = "Init";
        }

        public void PrintObjects(String para1, String para2)
        {
        }
    }

    class Program
    {
        static void Main(string[] args)
        {

            Stopwatch stopWatch = new Stopwatch();
            int times = 10000000;

            var dispatcher = new ActionMethodDispatcher(typeof(TestClass).GetMethod("PrintObjects"));

            var testClass = new TestClass();

            testClass.State = "Expression Call";

            stopWatch.Start();

            for (int i = 0; i < times; i++)
            {
                dispatcher.Execute(testClass, new object[] { "Hello", "World" });
            }


            stopWatch.Stop();

            Console.WriteLine("Expression Call use: " + stopWatch.Elapsed);


            var mydispatcher = new RelectionDispatcher(typeof(TestClass).GetMethod("PrintObjects"));
            testClass.State = "Reflect Call";

            stopWatch.Reset();
            stopWatch.Start();
            for (int i = 0; i < times; i++)
            {
                mydispatcher.Execute(testClass, new object[] { "Hello", "World" });
            }

            stopWatch.Stop();

            Console.WriteLine("Reflect Call use: " + stopWatch.Elapsed);
        }
    }
}

运行结果:

Expression Call use: 00:00:00.3916032
Reflect Call use: 00:00:09.4091986

ActionMethodDispatcher的性能要比ReflectDispatcher的性能高20多倍。好吧,这次Reflect的调用真是完败啊,为了这20多倍的性能,我们就是再多写20多倍的代码也在所不惜啊。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值