首页 新闻 会员 周边

探讨一个问题(冲积分ing,结贴时再加分,拟计划50分):表达式与反射性能优劣

0
[已解决问题] 解决于 2014-09-28 10:40

参考博问:  表达式树反射

这个博问的发起者说表达式的性能要高于反射,我也没较真,理论分析,似乎应该高一点的。

但是我的实验却相反:

            var paramExp1 = Expression.Parameter(typeof(string), "a");

            var method = typeof(string).GetMethod("ToCharArray", new Type[0]);
            var callExpression = Expression.Call(paramExp1, method);

            var tmp = Expression.Lambda(callExpression, paramExp1).Compile();

            Stopwatch methodWatch = new Stopwatch();
            methodWatch.Start();
            for(int i = 0; i < 1000; i++)
            {
                method.Invoke("aaa", new object[0]);
            }
            methodWatch.Stop();
            Stopwatch expWatch = new Stopwatch();
            expWatch.Start();
            for (int i = 0; i < 1000; i++)
            {
                tmp.DynamicInvoke("aaa");
                //method.Invoke("aaa", new object[0]);
            }
            expWatch.Stop();
            var t1 = methodWatch.ElapsedTicks;
            var t2 = expWatch.ElapsedTicks;

以上实验,t1的值在1000-2000之间,而t2则在5000-7000之间。

问题补充:

在网上看了一段代码,测试不同性能的,如下:

    public class CallTest
    {
        class Student
        {
            public string Name { get; set; }
        }

        static double Test(int loop, Student stu, Func<Student, string> action)
        {
            var watch = Stopwatch.StartNew();
            string s = null;
            for (var i = 0; i < loop; i++)
                s = action(stu);
            return watch.ElapsedTicks;
        }

        static Func<Student, string> NativeGetter()
        {
            return s => s.Name;
        }
        static Func<Student, string> ReflectedGetter()
        {
            var type = typeof(Student);
            var prop = type.GetProperty("Name");
            return s => (string)prop.GetValue(s, null);
        }
        static Func<Student, string> EmittedGetter()
        {
            var dm = new DynamicMethod(name: "EmittedGetter", returnType: typeof(string), parameterTypes: new[] { typeof(Student) }, owner: typeof(Student));
            var type = typeof(Student); var prop = type.GetMethod("get_Name");
            var il = dm.GetILGenerator(); 
            il.Emit(OpCodes.Ldarg_0); 
            il.Emit(OpCodes.Call, prop);
            il.Emit(OpCodes.Ret);
            return (Func<Student, string>)dm.CreateDelegate(typeof(Func<Student, string>));
        }

        static Func<Student, string> ExpressionGetter()
        {
            var type = typeof(Student); 
            var prop = type.GetMethod("get_Name"); 
            ParameterExpression pa = Expression.Parameter(typeof(Student)); 
            Expression body = Expression.Call(pa, prop); 
            return Expression.Lambda<Func<Student, string>>(body, pa).Compile();
        }

        static Func<Student, string> DynamicGetter()
        {
            return s => { dynamic d = s; return d.Name; };
        }

        [MethodImpl(MethodImplOptions.NoOptimization)]
        public static void Run()
        {
            int loop = 5000000;
            while (loop > 0)
            {
                var stu = new Student { Name = "Mike" };
                var dynamic = Test(loop, stu, DynamicGetter());
                var expression = Test(loop, stu, ExpressionGetter());
                var native = Test(loop, stu, NativeGetter());
                var emitted = Test(loop, stu, EmittedGetter());
                var reflected = Test(loop, stu, ReflectedGetter());
                Console.WriteLine(loop);
                Console.WriteLine("native:{1}{0}dynamic:{2}{0}emit:{3}{0}expression:{4}{0}reflection:{5}{0}", Environment.NewLine, 1, dynamic / native, emitted / native, expression / native, reflected / native);
                loop /= 10;
            }
            Console.ReadKey(); 
        }
    }


感觉,expression的性能很稳定,无论5次还是5百万次,都是2倍多点。

519740105的主页 519740105 | 大侠五级 | 园豆:5810
提问于:2014-09-05 11:20
< >
分享
最佳答案
0

我测试了一下,按照你这个写法,大概是5:1 (Expression:Reflect),关注中。

奖励园豆:5
爱编程的大叔 | 高人七级 |园豆:30839 | 2014-09-05 11:56

那有纯粹的Expression来替代Reflector?

519740105 | 园豆:5810 (大侠五级) | 2014-09-05 13:31

@519740105:  感觉表达式树比较反人类思维。

如果用于底层,作个ORM啊,或是系统框架之类的,

会好一点,但平时这样编程会把人整疯的。

我对于软件公司的构思,一直是抽象思维的人与具像思维的两组人。

但中间协调的这个如何起作用,一直都有疑惑。唉!

爱编程的大叔 | 园豆:30839 (高人七级) | 2014-09-05 14:45

@爱编程的大叔: 

把dynamicinvoke修改为直接执行(设置lambda的代理类型能解决):

var del = Expression.Lambda<Func<string, char[]>>(callExpression, new ParameterExpression[] { paramExp1 }).Compile(); 

从而,可以在调用的时候:

del("aaa");

这样就性能大大提高了。

 

我再想,怎么把这个过程封装起来,从而提高效率。

519740105 | 园豆:5810 (大侠五级) | 2014-09-05 14:59
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册