저는 주로 재미와 학습을 위해 최근에 몇 가지 최적화를하고 있는데, 몇 가지 질문이 떠오른 것을 발견했습니다.호기심 : 컴파일시 Expression <...>이 최소 DynamicMethod보다 빠르게 실행되는 이유는 무엇입니까?
먼저, 질문 :
- 내가 DynamicMethod를 사용하여 메모리 방법을 구성하고, 디버거를 사용 vieweing 날 때 생성 된 어셈블리 코드를 한 단계에 대한 방법이 존재 디스어셈블러 뷰의 코드? 디버거가 나를위한 모든 방법을 단계적으로 수행하는 것처럼 보입니다
- 아니면 가능하지 않은 경우 생성 된 IL 코드를 어셈블리로 디스크에 저장하여 Reflector으로 검사 할 수 있습니까?
- 내 간단한 추가 메서드 (Int32 + Int32 => Int32)의
Expression<...>
버전이 최소 DynamicMethod 버전보다 빠르게 실행되는 이유는 무엇입니까?
다음은 짧고 완전한 프로그램입니다.
DynamicMethod: 887 ms
Lambda: 1878 ms
Method: 1969 ms
Expression: 681 ms
내가 람다 및 방법은 높은 값을 호출 예상하지만, DynamicMethod 버전은 (아마도 Windows 및 다른 프로그램에 의한 변화) 지속적으로 약 30-50% 느립니다 : 내 시스템에서 출력됩니다. 누구든지 그 이유를 아나? Expression<>
통해 생성 방법은 어떤을 통과하지 않는 동안,
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;
}
}
}
흥미로운 질문입니다. WinDebug 및 SOS를 사용하여 이러한 종류의 문제를 해결할 수 있습니다. 나는 내 블로그에서 많은 달 전에했던 비슷한 분석을 한 걸음 한 발 게시했다. http://blog.barrkel.com/2006/05/clr-tailcall-optimization-or-lack.html –
나는 핑을해야한다고 생각했다. JIT를 한 번 호출하지 않아도 JIT를 강제 실행하는 방법을 알았습니다. 'restrictedSkipVisibility' DynamicMethod 생성자 인자를 사용하십시오. 컨텍스트 (코드 보안)에 따라 사용 가능하지 않을 수 있습니다. –
정말 좋은 질문입니다. 첫째,이 유형의 프로파일 링을 위해 나는 릴리즈/콘솔을 사용할 것입니다 - 그래서'Debug.WriteLine'은 제자리에서 보이지 않습니다; 하지만 Console.WriteLine이라도 내 통계는 비슷합니다 : DynamicMethod : 630 ms 람다 : 561 ms 방법 : 553 ms Expression : 360 ms 아직 찾고 있어요 ... –