gpt4 book ai didi

c# - DynamicMethod 比已编译的 IL 函数慢得多

转载 作者:太空狗 更新时间:2023-10-29 18:05:29 26 4
gpt4 key购买 nike

我写了一个简单的对象复制器来复制公共(public)属性。我不明白为什么 Dynamic 方法比 c# 版本慢很多。

时长

C# 方法:4,963 毫秒

动态方法:19,924 毫秒

请注意 - 因为我在启动秒表之前运行动态方法 - 持续时间不包括编译阶段。我在调试和 Release模式、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

如果你读了两遍,我很感激。我最初将此发布在: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.

最佳答案

这有点晚了,但是如果您在 .NET 4 中为您的所有程序集设置一些安全属性,并且您使用内置的委托(delegate)类型——或具有相同安全属性的委托(delegate)——你将会看到相当大的性能提升。

以下是您需要的属性:

[assembly: AllowPartiallyTrustedCallers]
[assembly: SecurityTransparent]
[assembly: SecurityRules(SecurityRuleSet.Level2,SkipVerificationInFullTrust=true)]

这实际上似乎有点错误。但是因为你说你的代码不会提高安全权限,你不会阻止部分信任的调用者,所以如果你使用 skipVisibility=true完全信任,调用 Func<int,int>委托(delegate)基本上应该避免几乎所有的权限检查。

还有一件事,因为这些是委托(delegate),如果您将它们视为实例方法,您将获得最佳性能,即使它们不是。也就是说总是使用两者之一 Delegate.CreateDelegate接受 firstArgument 的方法参数并向您的委托(delegate)添加初始对象引用。

考虑构建 DynamicMethodskipVisibility=true ,但没有指定所有者。分配所有者允许您运行 unverifiable code .你可以用它做一些非常糟糕的事情,所以我会避免它,除非你知道你在做什么。

关于c# - DynamicMethod 比已编译的 IL 函数慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13431573/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com