Friday, October 05, 2007

Dynamic Method Performance

In einem interessanten Artikel im MSDN Magazine wird auf unterschiedliche Performance Probleme, im Speziellen im Zusammenhang mit Reflection, eingegangen. Mich interessierte vor allem die gelobte Performance der dynamischen Methoden, die seit der .NET Framework Version 2.0 zur Verfügung stehen. Eine einfache Testanwendung hat gezeigt, dass der Artikel recht behält.
In der Testanwendung wird einem Objekt ein String eine Million mal zugewiesen. Dies zuerst direkt verdrahtet, danach mit dynamischer Methode und zuletzt via Reflection. Das Ergebnis ist eindeutig. Die direkt verdrahtete Methode ist natürlich die Schnellste, die dynamische Methode braucht dafür doppelt so lange (was ich immer noch sehr gut finde) und mittels Reflection dauert es 100mal länger. What a gain!
Übrigens, die Assembly habe ich mit Lutz's Reflector untersucht, um sicher zu stellen, dass die Schlaufe auch wirklich bei allen drei Varianten ausgeführt wird.

Und hier noch der Code:

public class Program
{
private delegate void DemoDelegate(Foo arg);

static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();

Foo f = new Foo();
stopwatch.Start();
for (int i = 0; i < 1000000; i++)
{
f.Text = "Hello World!";
}
stopwatch.Stop();
Console.WriteLine("Direct: {0}", stopwatch.Elapsed);

stopwatch.Reset();

DemoDelegate del = createMethod();
stopwatch.Start();
for (int i = 0; i < 1000000; i++)
{
del(f);
}
stopwatch.Stop();

Console.WriteLine("Dynamic method: {0}", stopwatch.Elapsed);

stopwatch.Reset();

PropertyInfo property = f.GetType().GetProperty("Text");
stopwatch.Start();
for (int i = 0; i < 1000000; i++)
{
property.SetValue(f, "Hello World!", null);
}
stopwatch.Stop();
Console.WriteLine("Reflection: {0}", stopwatch.Elapsed);


Console.ReadKey();
}

private static DemoDelegate createMethod()
{
Type[] parameterTypes = new Type[] { typeof(Foo) };
DynamicMethod method = new DynamicMethod("Demo", null, parameterTypes, typeof(Program));

ILGenerator iLGenerator = method.GetILGenerator();
iLGenerator.Emit(OpCodes.Ldarg_0);
iLGenerator.Emit(OpCodes.Ldstr, "Hello World!");
MethodInfo setMethod = typeof(Foo).GetProperty("Text").GetSetMethod();
iLGenerator.EmitCall(OpCodes.Call, setMethod, null);
iLGenerator.Emit(OpCodes.Ret);

return (DemoDelegate)method.CreateDelegate(typeof(DemoDelegate));
}
}

public class Foo
{
private string _text;

public string Text
{
get { return _text; }
set { _text = value; }
}
}

1 comment:

F Quednau said...

Nice Find. Didn't really know about the dynamic method strategy. Even after 2 years, Framework 2.0 manages to surprise.