19

ファイルとの間でデータを読み書きしています。ファイル内のデータは、float、double、int などにすることができます。型は実行時までわかりません。ファイルに格納されているデータ型を Tin と呼びます。データは、Tout 型の配列に読み書きされます。この型も実行時までわかりません。

コードシーケンスはこのようなものです。Open メソッドでは、Tin と Tout が既知であるため、既知のデータ型の読み取りおよび書き込みメソッドを作成できます。

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

読み書きループは何百万回も繰り返され、以下に示すように、リフレクションに依存して適切なメソッドを呼び出します。

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

パフォーマンス プロファイラーを使用してこのコードを調べると、ランタイムの読み取り/書き込みメソッドの呼び出しだけに時間が費やされると、膨大な量になることがわかります。

どうすればこれを高速化できますか。

4

3 に答える 3

29

はい、これは、リフレクション API が直接メソッド呼び出しよりも何千倍も遅いという事実によるものです。ただし、これを回避するための興味深い手法がいくつかあります。デリゲートを使用してリフレクションをキャッシュする方法については、Jon Skeet の記事を参照してください。

静的なセットアップ コストがかかりますが、それが完了すると、デリゲートを繰り返し呼び出す時間は、仮想メソッドの呼び出しに相当します。

同じことを実現するために、パッケージ化されたフレームワークもいくつかあります。

于 2012-04-25T10:44:09.767 に答える
8

これは、直接電話をかけるのとほぼ同じ速さで、何でもできます。

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);
    }
}
于 2017-01-07T00:48:22.467 に答える