簡體   English   中英

反射方法調用與委托調用的性能

[英]Performance of reflection method call vs delegate call

我的目標是編寫一個弱類型的 TryParse方法,該方法基本上支持所有可用的struct類型(int,long,float ...)

public static bool TryParse(Type type, string s, out object obj)

該實現將調用所提供type參數的TryParse方法(如果type為int ,則將調用int.TryPase並將out值作為對象返回)。

我通過反射實現了它,但是有一個主要的性能損失(正如我預期的那樣)

反思實施:

public static class ParserHelper
{
    public delegate bool TryParseDl(string str, out object obj);

    private static readonly HashSet<Type> ParsableStructs = new HashSet<Type>
    {
    typeof(int),
    typeof(uint),
    typeof(decimal),
    typeof(short),
    typeof(ushort),
    typeof(double),
    typeof(long),
    typeof(ulong),
    typeof(float),
    typeof(byte),
    typeof(sbyte)
    };

    public static readonly ReadOnlyDictionary<Type, TryParseDl> StructParsers;

    static ParserHelper()
    {
        StructParsers = new ReadOnlyDictionary<Type, TryParseDl>(CreateParsersForStructs());
    }

    /// Creates parsers for structs
            private static Dictionary<Type, TryParseDl> CreateParsersForStructs()
        {
            var parsers = new Dictionary<Type, TryParseDl>();
            foreach (var t in ParsableStructs)
            {
                parsers[t] = GetParserForStruct(t);
            }
            return parsers;
        }

    private static TryParseDl GetParserForStruct(Type targetType)
        {
            var methodInfo = targetType.GetMethod(
                "TryParse",
                BindingFlags.Public | BindingFlags.Static,
                Type.DefaultBinder,
                new[] { typeof(string), targetType.MakeByRefType() },
                null);

            return (string str, out object obj) =>
                {
                    if (string.IsNullOrEmpty(str))
                    {
                        obj = targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
                        return true;
                    }
                    var inputParameters = new object[] { str, null };
                    var tryParseResult = (bool)methodInfo.Invoke(null, inputParameters);
                    obj = inputParameters[1];
                    return tryParseResult;
                };
        }
}

這是性能測試:

public class Program
{
    public static void Main()
    {
        Stopwatch s = new Stopwatch();
        string str = "100";     
        s.Start();
        for(int j = 0;j<100;j++)
        {
            int i;
            int.TryParse(str,out i);

        }
        s.Stop();
        Console.WriteLine(s.Elapsed);
        s.Reset();
        s.Start();
        var parser = ParserHelper.StructParsers[typeof(int)];   
        for(int j = 0;j<100;j++)
        {                           
            object o;
            parser(str, out o);
        }

        s.Stop();
        Console.WriteLine(s.Elapsed);
    }
}

平均結果是反射調用比直接調用慢了200倍(在100次重復上)。 演示反射測試的小提琴

我試圖通過使用緩存的委托來提高性能:

public static class StructParserExtensions
{
    public static bool IntToObjParse(string str, out object obj)
    {
        int i;
        var result = int.TryParse(str, out i);
        obj = result ? (object)i : null;
        return result;
    }

    public static bool LongToObjParse(string str, out object obj)
    {
        long i;
        var result = long.TryParse(str, out i);
        obj = result ? (object)i : null;
        return result;
    }

    //implementations for other types goes here

}


public static class ParserHelper
{
    public delegate bool TryParseDl(string str, out object obj);

    public static readonly ReadOnlyDictionary<Type, TryParseDl> StructParsers;

    static ParserHelper()
    {
        StructParsers = new ReadOnlyDictionary<Type, TryParseDl>(CreateParsersForStructs());
    }

    /// Creates parsers for structs
    /// </summary>
    /// <returns>Dictionary</returns>
    private static Dictionary<Type, TryParseDl> CreateParsersForStructs()
    {

        var parsers = new Dictionary<Type, TryParseDl>();
        parsers[typeof(int)] = StructParserExtensions.IntToObjParse;                      
        parsers[typeof(long)] = StructParserExtensions.LongToObjParse;           
        return parsers;
    }           
}

我假設使用委托將大大提高性能,因此它將接近直接調用,但我錯了它仍然慢約100倍(在100 reties) 這里是小提琴

我的問題是:

  1. 雖然我看到了多個示例,其中將反射調用轉換為委托調用會產生差異,但在這種情況下它不起作用。 為什么?
  2. 在這種情況下,有什么辦法可以改善性能嗎?

你只是測試100次迭代。 您主要測試一次性啟動開銷。 增加迭代次數,直到每次測試需要1秒鍾。 這樣,開銷就會消失在噪音中。

目前,您的代碼運行時間為.5毫秒。 這遠遠噪音范圍內。 修好后我得到:

00:00:00.9711365
00:00:01.0958751 //Slightly slower

該基准使用1e7次迭代,而前一次使用1e2。 另外,請確保在Release模式下進行測試,而不需要調試器附加您關心的位數。

有什么不對:

        private object Converter(object inVal, Type t)
    {
        return Convert.ChangeType(inVal, t);
    }

如前所述。 通過100次迭代,您最有可能只測量開銷。

我進一步測試了一下。 我將您的代碼加入到一個並運行450次迭代以獲得一些統計數據。 我把它設置為解析10萬次(10 ^ 7)

這是代碼: http//pastebin.com/65dhdX9t

這是最后幾次迭代的結果:
m-method,d-delegate,r-reflection 統計 把它們加起來:
- 代表團是aprox。 直接呼叫速度慢1.195倍
- 反思是aprox。 比直接呼叫慢6.105倍

希望能幫助到你! 它確實幫助我說服我從反思轉移到代表團。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM