DynamicMethod的是比编译IL功能更慢 [英] DynamicMethod is much slower than compiled IL function

查看:209
本文介绍了DynamicMethod的是比编译IL功能更慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个简单的对象复印机那份公共属性。
我想不通,为什么动态方法比C#版本慢了许多。



持续时间



C#方法:4963毫秒



动态方法:19924毫秒



需要注意的是 - 当我运行动态方法启动秒表前 - 时间不包括编译阶段。
我运行在调试和发布模式,在x86和x64模式,并从VS和具有大致相同的结果(动态方法慢400%)的命令行。

  const int的NBRECORDS = 100 * 1000 * 1000; 

公共类Person
{
私人诠释mSomeNumber;

公共字符串名字{获得;组; }
公共字符串名字{获得;组; }
公众的DateTime DATEOFBIRTH {搞定;组; }
公众诠释SomeNumber
{
{返回mSomeNumber; }
集合{mSomeNumber =价值; }
}
}

公共静态动作< T1,T2> CreateCopier< T1,T2>()
{
无功甲=新的DynamicMethod的(复制,空,新类型[] {typeof运算(T1)的typeof(T2)},restrictedSkipVisibility:真正的);
的ILGenerator IL = meth.GetILGenerator();
INT CPT = 0;

VAR stopHere = typeof运算(程序).GetMethod(StopHere);

的foreach(typeof运算中(T1 VAR MI1).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
VAR MI2 = typeof运算(T2).GetProperty(MI1。名称,BindingFlags.Public | BindingFlags.Instance);
如果(MI1 = NULL&放大器;!&安培; MI2!= NULL)
{
CPT ++;
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt,mi1.GetMethod);
il.Emit(OpCodes.Callvirt,mi2.SetMethod);
}
}
il.Emit(OpCodes.Ret);

变种DLG = meth.CreateDelegate(typeof运算(动作< T1,T2>));
回报率(动作< T1,T2>)DLG;
}

静态无效的主要(字串[] args)
{
变种PERSON1 =新的Person(){名字=帕斯卡,姓氏=Ganaye ,出生日期=新的日期时间(1909,5,1),SomeNumber = 23456};
变种PERSON2 =新的Person();

VAR copyUsingAMethod =(动作<人,人>)CopyPerson;
VAR copyUsingADynamicMethod = CreateCopier<人,人>();

copyUsingAMethod(PERSON1,PERSON2); // 4882毫秒
变种SW = Stopwatch.StartNew();
的for(int i = 0; I< NBRECORDS;我++)
{
copyUsingAMethod(PERSON1,PERSON2);
}
Console.WriteLine({0}毫秒,sw.ElapsedMilliseconds);

copyUsingADynamicMethod(PERSON1,PERSON2); // 19920毫秒
SW = Stopwatch.StartNew();
的for(int i = 0; I< NBRECORDS;我++)
{
copyUsingADynamicMethod(PERSON1,PERSON2);
}
Console.WriteLine({0}毫秒,sw.ElapsedMilliseconds);


Console.ReadKey(截距:真);
}

私有静态无效CopyPerson(人PERSON1,人PERSON2)
{
person2.FirstName = person1.FirstName;
person2.LastName = person1.LastName;
person2.DateOfBirth = person1.DateOfBirth;
person2.SomeNumber = person1.SomeNumber;
}



从我可以调试这两种方法具有相同的IL代码。

  IL_0000:NOP 
IL_0001:ldarg.1
IL_0002:ldarg.0
IL_0003:callvirt System.String get_FirstName()/ DuckCopy.SpeedTests.Program +人
IL_0008:callvirt虚空set_FirstName(System.String)/DuckCopy.SpeedTests.Program+Person
IL_000d:NOP
IL_000e:ldarg .1
IL_000f:ldarg.0
IL_0010:callvirt System.String get_LastName()/ DuckCopy.SpeedTests.Program +人
IL_0015:callvirt虚空set_LastName(System.String)/DuckCopy.SpeedTests 。程序+人
IL_001a:NOP
IL_001b:ldarg.1
IL_001c:ldarg.0
IL_001d:callvirt的System.DateTime get_DateOfBirth()/ DuckCopy.SpeedTests.Program +人
IL_0022:callvirt虚空set_DateOfBirth(的System.DateTime)/DuckCopy.SpeedTests.Program+Person
IL_0027:NOP
IL_0028:ldarg.1
IL_0029:ldarg.0
IL_002a:callvirt的Int32 get_SomeNumber()/ DuckCopy.SpeedTests.Program +人
IL_002f:callvirt虚空set_SomeNumber(Int32)已/DuckCopy.SpeedTests.Program+Person
IL_0034:NOP
IL_0035:RET

如果你读这两次我applogize。
我张贴了这个原本在: http://www.codeproject.com/Answers / 494714 /灿27tplusfigureplusoutpluswhyplusthisplusDynamic
却没有得到我所希望的答案



编辑二零一二年十一月十七日15点11:

 删除NOP 
去除多余=,它来自我不知道在哪里。


解决方案

艾伦·N的代码项目中发现的问题
此问题出现了:在.NET框架4.0。



大的执行时间慢下来的时候是动态方法是使用DynamicMethod的与匿名集关联引起的(串,类型,类型[],布尔)构造函数。我猜想,.NET 4做得比以前的版本更安全检查,虽然我没有洞察到,或解释,什么是真正回事。



关联通过使用DynamicMethod的一个类型的方法(字符串,类型,类型[]类型,布尔)构造完全消除速度损失。



有MSDN上的一些注意事项这可能是相关的(如果只有我能理解他们!):




I wrote a simple object copier that copies public properties. I can't figure out why the Dynamic method is a lot slower than the c# version.

Durations

C# method : 4,963 ms

Dynamic method : 19,924 ms

Note that - as I run the dynamic method before starting the stopwatch - the duration do not include the compilation phase. I run that in Debug and Release mode, in x86 and x64 mode, and from VS and from the command line with roughly the same result (dynamic method is 400% slower).

        const int NBRECORDS = 100 * 1000 * 1000;

        public class Person
        {
            private int mSomeNumber;

            public string FirstName { get; set; }
            public string LastName { get; set; }
            public DateTime DateOfBirth { get; set; }
            public int SomeNumber
            {
                get { return mSomeNumber; }
                set { mSomeNumber = value; }
            }
        }

        public static Action<T1, T2> CreateCopier<T1, T2>()
        {
            var meth = new DynamicMethod("copy", null, new Type[] { typeof(T1), typeof(T2) }, restrictedSkipVisibility: true);
            ILGenerator il = meth.GetILGenerator();
            int cpt = 0;

            var stopHere = typeof(Program).GetMethod("StopHere");

            foreach (var mi1 in typeof(T1).GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                var mi2 = typeof(T2).GetProperty(mi1.Name, BindingFlags.Public | BindingFlags.Instance);
                if (mi1 != null && mi2 != null)
                {
                    cpt++;
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Callvirt, mi1.GetMethod);
                    il.Emit(OpCodes.Callvirt, mi2.SetMethod);
                }
            }
            il.Emit(OpCodes.Ret);

            var dlg = meth.CreateDelegate(typeof(Action<T1, T2>));
            return (Action<T1, T2>)dlg;
        }

        static void Main(string[] args)
        {
            var person1 = new Person() { FirstName = "Pascal", LastName = "Ganaye", DateOfBirth = new DateTime(1909, 5, 1), SomeNumber = 23456 };
            var person2 = new Person();

            var copyUsingAMethod = (Action<Person, Person>)CopyPerson;
            var copyUsingADynamicMethod = CreateCopier<Person, Person>();

            copyUsingAMethod(person1, person2); // 4882 ms
            var sw = Stopwatch.StartNew();
            for (int i = 0; i < NBRECORDS; i++)
            {
                copyUsingAMethod(person1, person2);
            }
            Console.WriteLine("{0} ms", sw.ElapsedMilliseconds);

            copyUsingADynamicMethod(person1, person2); // 19920 ms
            sw = Stopwatch.StartNew();
            for (int i = 0; i < NBRECORDS; i++)
            {
                copyUsingADynamicMethod(person1, person2); 
            }
            Console.WriteLine("{0} ms", sw.ElapsedMilliseconds);


            Console.ReadKey(intercept: true);
        }

        private static void CopyPerson(Person person1, Person person2)
        {
            person2.FirstName = person1.FirstName;
            person2.LastName = person1.LastName;
            person2.DateOfBirth = person1.DateOfBirth;
            person2.SomeNumber = person1.SomeNumber;
        }

From what I can debug the two methods have the same IL code.

IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.0
IL_0003: callvirt   System.String get_FirstName()/DuckCopy.SpeedTests.Program+Person
IL_0008: callvirt   Void set_FirstName(System.String)/DuckCopy.SpeedTests.Program+Person
IL_000d: nop
IL_000e: ldarg.1
IL_000f: ldarg.0
IL_0010: callvirt   System.String get_LastName()/DuckCopy.SpeedTests.Program+Person
IL_0015: callvirt   Void set_LastName(System.String)/DuckCopy.SpeedTests.Program+Person
IL_001a: nop
IL_001b: ldarg.1
IL_001c: ldarg.0
IL_001d: callvirt   System.DateTime get_DateOfBirth()/DuckCopy.SpeedTests.Program+Person
IL_0022: callvirt   Void set_DateOfBirth(System.DateTime)/DuckCopy.SpeedTests.Program+Person
IL_0027: nop
IL_0028: ldarg.1
IL_0029: ldarg.0
IL_002a: callvirt   Int32 get_SomeNumber()/DuckCopy.SpeedTests.Program+Person
IL_002f: callvirt   Void set_SomeNumber(Int32)/DuckCopy.SpeedTests.Program+Person
IL_0034: nop
IL_0035: ret

I applogize if you read this twice. I posted this originally in: http://www.codeproject.com/Answers/494714/Can-27tplusfigureplusoutpluswhyplusthisplusDynamic but did not get all the answers I hoped.

edited 17 nov 2012 15:11:

removed the nop
removed the extra ="" which came from I don't where.

解决方案

Alan N in code project found the problem This problem appeared in .Net framework 4.0.

The big slow down in execution time is caused when the dynamic method is associated with an anonymous assembly by using the DynamicMethod(string, Type, Type[], bool) constructor. I would guess that .NET 4 is doing more security checks than the previous versions, although I have no insight into, or explanation for, what is actually going on.

Associating the method with a Type by using the DynamicMethod(string, Type, Type[], Type, bool) constructor completely removes the speed penalty.

There are some notes on MSDN which may be relevant (if only I could understand them!):

这篇关于DynamicMethod的是比编译IL功能更慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆