反射方法调用与委托调用的性能

亚历克斯·阿特

我的目标是编写一个弱类型 TryParse方法,该方法基本上支持所有可用的结构类型(int,long,float ...)

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

该实现将调用TryParse提供的type参数方法(如果type为intint.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);
    }
}

平均结果是,反射调用比直接调用(在100个资源上)慢200倍。演示反射测试的小提琴

我试图通过使用缓存的委托来提高性能:

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. 在这种情况下,有什么方法可以提高性能?
usr

您正在测试100次迭代。您主要是在测试一次性启动开销。增加迭代次数,直到每个测试花费1秒。这样,开销就消失在噪音中了。

当前,您的代码运行0.5毫秒。那远不噪声范围内。修复后,我得到:

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

该基准测试使用1e7迭代,而前一个使用1e2。另外,请确保在释放模式下进行测试,而您所关注的位数上没有附加调试器。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

反射方法调用与委托调用的性能

来自分类Dev

从反射调用静态委托?

来自分类Dev

从反射调用静态委托?

来自分类Dev

用反射调用静态委托

来自分类Dev

无法调用委托方法

来自分类Dev

未调用委托方法

来自分类Dev

通过反射调用构造函数的性能

来自分类Dev

如何将通过反射获得的方法分配给委托?(或者:如何通过反射来加快方法调用的速度)

来自分类Dev

通过带有委托参数的反射调用泛型方法的问题

来自分类Dev

如何通过反射从不同的程序集中使用内部委托参数调用内部方法?

来自分类Dev

委托多个方法的方法调用

来自分类Dev

在 Func 委托中调用 Func 委托的方法

来自分类Dev

NSFetchedResultsControllerDelegate委托方法未调用

来自分类Dev

UIPageViewController委托方法未调用

来自分类Dev

委托方法没有被调用?

来自分类Dev

XCTest测试委托方法的调用

来自分类Dev

MFMailComposeViewController委托方法未调用

来自分类Dev

未调用NSURLSession委托方法

来自分类Dev

UITextField委托方法未调用

来自分类Dev

不再调用FBLoginView委托方法

来自分类Dev

XMLParser不调用委托方法

来自分类Dev

NSSplitViewController不调用委托方法

来自分类Dev

MFMailComposeViewController委托方法未调用

来自分类Dev

UIPageViewController委托方法未调用

来自分类Dev

未调用NSSplitView委托方法

来自分类Dev

委托方法未调用-iOS

来自分类Dev

UIImagePickerController不调用委托方法

来自分类Dev

如何调用UIWebview的委托方法?

来自分类Dev

未调用类委托方法