【发布时间】:2010-11-20 18:24:51
【问题描述】:
我目前正在做一些最后的优化,主要是为了好玩和学习,并发现了一些让我有几个问题的东西。
首先,问题:
- 当我通过使用DynamicMethod 构造内存中的方法并使用调试器时,在反汇编视图中查看代码时,有什么方法可以让我进入生成的汇编代码?调试器似乎只是为我跳过了整个方法
- 或者,如果这不可能,我是否可以以某种方式将生成的 IL 代码作为程序集保存到磁盘,以便我可以使用 Reflector 检查它?
- 为什么我的简单加法方法 (Int32+Int32 => Int32) 的
Expression<...>版本比最小的 DynamicMethod 版本运行得更快?
这是一个简短而完整的演示程序。在我的系统上,输出是:
DynamicMethod: 887 ms
Lambda: 1878 ms
Method: 1969 ms
Expression: 681 ms
我预计 lambda 和方法调用具有更高的值,但 DynamicMethod 版本始终慢约 30-50%(可能因 Windows 和其他程序而异)。有人知道原因吗?
这是程序:
using System;
using System.Linq.Expressions;
using System.Reflection.Emit;
using System.Diagnostics;
namespace Sandbox
{
public class Program
{
public static void Main(String[] args)
{
DynamicMethod method = new DynamicMethod("TestMethod",
typeof(Int32), new Type[] { typeof(Int32), typeof(Int32) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Ret);
Func<Int32, Int32, Int32> f1 =
(Func<Int32, Int32, Int32>)method.CreateDelegate(
typeof(Func<Int32, Int32, Int32>));
Func<Int32, Int32, Int32> f2 = (Int32 a, Int32 b) => a + b;
Func<Int32, Int32, Int32> f3 = Sum;
Expression<Func<Int32, Int32, Int32>> f4x = (a, b) => a + b;
Func<Int32, Int32, Int32> f4 = f4x.Compile();
for (Int32 pass = 1; pass <= 2; pass++)
{
// Pass 1 just runs all the code without writing out anything
// to avoid JIT overhead influencing the results
Time(f1, "DynamicMethod", pass);
Time(f2, "Lambda", pass);
Time(f3, "Method", pass);
Time(f4, "Expression", pass);
}
}
private static void Time(Func<Int32, Int32, Int32> fn,
String name, Int32 pass)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (Int32 index = 0; index <= 100000000; index++)
{
Int32 result = fn(index, 1);
}
sw.Stop();
if (pass == 2)
Debug.WriteLine(name + ": " + sw.ElapsedMilliseconds + " ms");
}
private static Int32 Sum(Int32 a, Int32 b)
{
return a + b;
}
}
}
【问题讨论】:
-
非常好的问题。首先,对于这种类型的分析,我会使用发布/控制台——所以
Debug.WriteLine看起来不合适;但即使使用Console.WriteLine,我的统计数据也相似:DynamicMethod:630 毫秒 Lambda:561 毫秒方法:553 毫秒表达式:360 毫秒我还在寻找... -
有趣的问题。这类事情可以使用 WinDebug 和 SOS 解决。我在我的博客blog.barrkel.com/2006/05/clr-tailcall-optimization-or-lack.html 中逐步发布了我很多个月前所做的类似分析
-
我想我应该 ping 你 - 我发现了如何强制 JIT 而不必调用该方法一次。使用
restrictedSkipVisibilityDynamicMethod 构造函数参数。根据上下文(代码安全性),它可能不可用。 -
好问题!关于#1,我不认为 DynamicMethods 是可调试的(与发出程序集相反)。但是,您可以哑巴并分析 DynamicMethod 的主体。我使用ILVisualizer - 够花哨和方便。问候,瓦迪姆
-
stackoverflow.com/questions/11023993/… Tony THONG
标签: c# profiling reflection.emit expression dynamicmethod