我写了一个复制公共属性的简单对象复制器。 我无法弄清楚为什么Dynamic方法比c#版本慢得多。
持续时间
C#方法:4,963 ms
动态方法:19,924 ms
请注意 - 当我在启动秒表之前运行动态方法时 - 持续时间不包括编译阶段。 我在调试和发布模式下,在x86和x64模式下运行,从VS和命令行运行,结果大致相同(动态方法慢400%)。
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;
}
从我可以调试的两个方法有相同的IL代码。
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
如果你读了两次,我会applogize。 我最初发布在:http://www.codeproject.com/Answers/494714/Can-27tplusfigureplusoutpluswhyplusthisplusDynamic 但没有得到我希望的所有答案。
编辑于2012年11月17日15:11:
removed the nop
removed the extra ="" which came from I don't where.
答案 0 :(得分:13)
这有点晚了,但如果您在所有程序集上的 .NET 4 中设置了一些安全属性,并且您使用内置委托类型或具有相同安全属性的委托 - 您会看到很大的性能提升。
以下是您需要的属性:
[assembly: AllowPartiallyTrustedCallers]
[assembly: SecurityTransparent]
[assembly: SecurityRules(SecurityRuleSet.Level2,SkipVerificationInFullTrust=true)]
这实际上似乎有点像个bug。但是因为你说你的代码不会提高安全权限,所以你不会阻止部分信任的调用者,所以如果你完全信任skipVisibility=true
,那么调用Func<int,int>
代理基本上应该避免所有的许可检查。
还有一件事,因为这些是委托,如果你把它们视为实例方法,你将获得最佳性能,即使它们不是。也就是说,始终使用接受Delegate.CreateDelegate
参数的两个firstArgument
方法之一,并向您的委托添加初始对象引用。
考虑使用DynamicMethod
构建skipVisibility=true
,但不指定所有者。通过分配所有者,您可以运行unverifiable code。你可以做一些真正搞砸的东西,所以除非你知道你在做什么,否则我会避免它。
答案 1 :(得分:11)
.NET
Framework 4.0中所做的更改引入了此问题。我在CodeProject上找到了用户“a solution”发布的Alan-N。
DynamicMethod
与"system-provided, fully trusted, security-transparent assembly,"关联,如果您使用DynamicMethod(string, Type, Type[], bool)
构造函数,则会导致执行时间大幅减慢。似乎.NET 4正在进行比以前版本更多的安全检查,尽管我对实际发生的事情没有任何了解或解释。
将DynamicMethod
与Type
相关联(改为使用DynamicMethod(string, Type, Type[], Type, bool)
构造函数;请注意额外的Type
- 值参数'owner')完全消除速度惩罚。
MSDN上有一些注释可能是相关的(如果我能理解它们的话!):