Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MethodInfo.Invoke performance issue

Tags:

c#

.net

invoke

I am reading and writing data to and from a file. The data in the file can be floats, doubles, ints etc. The type is not known until runtime. I will refer to data type stored in the file as Tin. Data is read into or written from arrays of type Tout. This type too is not known until runtime.

The code sequence is something like this. In the Open method Tin and Tout are known, we can create read and write methods for the known data types.

Open(...)
{
   MethodInfo ReadMethod = typeof(...)GetMethod("ReadGeneric").MakeGenericMethod(new Type[] {typeof(Tin), typeof(Tout)}));
}

The read write loops repeat millions of times and rely on reflection to invoke the appropriate methods as shown below.

Read loop
{
   var values = (Tout[])ReadMethod.Invoke(this,new object[]{index});
   process ...
}

When examining this code using a performance profiler I find that c collosal amount if time is spent just invoking the runtime read write methods.

How do I speed this up.

like image 318
Basil Furdas Avatar asked Apr 25 '12 10:04

Basil Furdas


2 Answers

Yes, this is due to the fact that the reflection API is thousands of times slower than direct method calls. There are some interesting techniques to work around this however. Check out Jon Skeet's article on using delegates to cache reflection.

There is a static setup cost but once you have done that the time to invoke the delegate repeatedly is equivalent to virtual method calls.

There are also some pre-packaged frameworks to achieve the same thing.

like image 62
Dr. Andrew Burnett-Thompson Avatar answered Oct 06 '22 03:10

Dr. Andrew Burnett-Thompson


This'll do anything for ya, almost as fast as a direct call.

using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

public class FastMethodInfo
{
    private delegate object ReturnValueDelegate(object instance, object[] arguments);
    private delegate void VoidDelegate(object instance, object[] arguments);

    public FastMethodInfo(MethodInfo methodInfo)
    {
        var instanceExpression = Expression.Parameter(typeof(object), "instance");
        var argumentsExpression = Expression.Parameter(typeof(object[]), "arguments");
        var argumentExpressions = new List<Expression>();
        var parameterInfos = methodInfo.GetParameters();
        for (var i = 0; i < parameterInfos.Length; ++i)
        {
            var parameterInfo = parameterInfos[i];
            argumentExpressions.Add(Expression.Convert(Expression.ArrayIndex(argumentsExpression, Expression.Constant(i)), parameterInfo.ParameterType));
        }
        var callExpression = Expression.Call(!methodInfo.IsStatic ? Expression.Convert(instanceExpression, methodInfo.ReflectedType) : null, methodInfo, argumentExpressions);
        if (callExpression.Type == typeof(void))
        {
            var voidDelegate = Expression.Lambda<VoidDelegate>(callExpression, instanceExpression, argumentsExpression).Compile();
            Delegate = (instance, arguments) => { voidDelegate(instance, arguments); return null; };
        }
        else
            Delegate = Expression.Lambda<ReturnValueDelegate>(Expression.Convert(callExpression, typeof(object)), instanceExpression, argumentsExpression).Compile();
    }

    private ReturnValueDelegate Delegate { get; }

    public object Invoke(object instance, params object[] arguments)
    {
        return Delegate(instance, arguments);
    }
}
like image 39
Daniel Henry Avatar answered Oct 06 '22 03:10

Daniel Henry