zoukankan      html  css  js  c++  java
  • 性能问题在于你想不到的任何地方

    性能问题在于你想不到的任何地方!

     

    今天在做blqw.Json反序列化的优化工作的时候发现一个问题,在反序列化一个非常简单的对象

    复制代码
    public class SimpleObject
    {
        public static SimpleObject New()
        {
            return new SimpleObject
            {
                Scores = new int[]{1,2,3,4,5,6,7,8,9,0}
            };
        }
        public int[] Scores { get; set; }
    }
    复制代码

    在性能上我居然和想象中的相差非常大,看结果

    我第一时间想到的就是会不会Dictionary引起的?

    复制代码
    delegate bool TryParseHandler(bool nullable, string str, out object value);
    Dictionary<TypeCode, TryParseHandler> TryParseMethods = new Dictionary<TypeCode, TryParseHandler>();
    protected JsonConvert()
    {
        if (Instance == null)
        {
            TryParseMethods = new Dictionary<TypeCode, TryParseHandler>();
            TryParseMethods.Add(Type.GetTypeCode(typeof(Boolean)), TryParseBoolean);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Byte)), TryParseByte);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Char)), TryParseChar);
            TryParseMethods.Add(Type.GetTypeCode(typeof(DateTime)), TryParseDateTime);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Decimal)), TryParseDecimal);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Double)), TryParseDouble);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Int16)), TryParseInt16);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Int32)), TryParseInt32);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Int64)), TryParseInt64);
            TryParseMethods.Add(Type.GetTypeCode(typeof(SByte)), TryParseSByte);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Single)), TryParseSingle);
            TryParseMethods.Add(Type.GetTypeCode(typeof(UInt16)), TryParseUInt16);
            TryParseMethods.Add(Type.GetTypeCode(typeof(UInt32)), TryParseUInt32);
            TryParseMethods.Add(Type.GetTypeCode(typeof(UInt64)), TryParseUInt64);
            TryParseMethods.Add(Type.GetTypeCode(typeof(Guid)), TryParseGuid);
            TryParseMethods.Add(Type.GetTypeCode(typeof(String)), TryParseString);
        }
        else
        {
            TryParseMethods = Instance.TryParseMethods;
        }
    }
    
    public bool TryParse(Type type, string str, out object value)
    {
        bool nullable;
        //处理可空值类型
        Type t;
        t = Nullable.GetUnderlyingType(type);
        if (t != null)
        {
            nullable = true;
            type = t;
        }
        else
        {
            nullable = false;
        }
    
        TryParseHandler tryparse;
        if (TryParseMethods.TryGetValue(Type.GetTypeCode(type), out tryparse))
        {
            return tryparse(nullable, str, out value);
        }
        else
        {
            value = null;
            return false;
        }
    }
    复制代码

    我直接改成了switch,我要查看最坏情况下的性能,所以把int32的case分支放到的最下面

    复制代码
    switch (Type.GetTypeCode(type))
    {
        case TypeCode.Boolean:
            return TryParseBoolean(nullable, str, out value);
        case TypeCode.Byte:
            return TryParseByte(nullable, str, out value);
        case TypeCode.Char:
            return TryParseChar(nullable, str, out value);
        case TypeCode.DateTime:
            return TryParseDateTime(nullable, str, out value);
        case TypeCode.Decimal:
            return TryParseDecimal(nullable, str, out value);
        case TypeCode.Double:
            return TryParseDouble(nullable, str, out value);
        case TypeCode.Int16:
            return TryParseInt16(nullable, str, out value);
        case TypeCode.Int64:
            return TryParseInt64(nullable, str, out value);
        case TypeCode.SByte:
            return TryParseSByte(nullable, str, out value);
        case TypeCode.Single:
            return TryParseSingle(nullable, str, out value);
        case TypeCode.String:
            return TryParseString(nullable, str, out value);
        case TypeCode.UInt16:
            return TryParseUInt16(nullable, str, out value);
        case TypeCode.UInt32:
            return TryParseUInt32(nullable, str, out value);
        case TypeCode.UInt64:
            return TryParseUInt64(nullable, str, out value);
        case TypeCode.DBNull:
        case TypeCode.Empty:
            value = null;
            return str == "null" || str == "undefined" || str == null;
        case TypeCode.Int32:
            return TryParseInt32(nullable, str, out value);
        case TypeCode.Object:
        default:
            value = null;
            return false;
    }
    复制代码

    几乎是没有什么差别的

    所以我果断放弃了Dictionary,我可以把常用的类型(int,string,double等)放到前面,即使最差情况也和Dictionary一样,大部分情况下都会比Dictionary好

    接着我就想会不会是因为我多处理了一个可空值类型,所以性能上会比fastJson慢?(fastJson在反序列化可空值类型的时候是报错的)

    然后我把处理可控制类型的地方给注释了,看看到底是不是判断可空值类型的时候引起的

    复制代码
    bool nullable;
    //处理可空值类型
    //Type t;
    //t = Nullable.GetUnderlyingType(type);
    //if (t != null)
    //{
    //    nullable = true;
    //    type = t;
    //}
    //else
    {
        nullable = false;
    }
    复制代码

    结果几乎没有变化!!!

    嗯,我把TryParseInt32(nullable, str, out value);中处理可控制类型的方法也注释了试试

    复制代码
    public virtual bool TryParseInt32(bool nullable, string str, out object value)
    {
        Int32 v;
        if (Int32.TryParse(str, out v))
        {
            //value = nullable ? new Nullable<Int32>(v) : v;
            value = v;
            return true;
        }
        else
        {
            value = null;
            return false;
        }
    }
    复制代码

    我了个去,性能真的提高了!!

    但是非常奇怪的是,我以前做过测试,判断是几乎不消耗性能的,为什么区区10W次的判断能相差10多毫秒??

    难道问题在三元表达式???

    我试着把三元表达式改成if..else...

    复制代码
    public virtual bool TryParseInt32(bool nullable, string str, out object value)
    {
        Int32 v;
        if (Int32.TryParse(str, out v))
        {
            if (nullable)
            {
                value = new Nullable<Int32>(v);
            }
            else
            {
                value = v;
            }
            return true;
        }
        else
        {
            value = null;
            return false;
        }
    }
    复制代码

    尼玛坑爹了好吗!!!!

    改成if...else...之后完全和之前的一模一样啊...

    三元表达式这是想表达什么呢?

    ============================================================

    以下感谢博友Pandora的指正

    原本以为是三元表达式的问题,所以也就没有深究下去了

    听了博友Pandora的建议之后回头想想确实也是这么一个道理

    所有方法不可能按照返回值类型做出推断

    为了验证这个说法,只需要设置一个var就可以看出来了

    var 告诉我们 他是可空值类型

    这就说明了 即使是int也会被换成int?

    所以只要改成

    这样就没问题了.....

    好吧好吧  我错怪三元表达式了,三元兄对不起啦~~~~

    我写的文章,除了纯代码,其他的都是想表达一种思想,一种解决方案.希望各位看官不要局限于文章中的现成的代码,要多关注整个文章的主题思路,谢谢
     
    分类: ASP.NETC#
  • 相关阅读:
    接口测试基础07
    性能测试基础01
    接口测试基础06
    将java list转换为js的数组
    java 网络编程
    java分页
    单例模式
    适配器模式
    抽象工厂模式
    工厂模式
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3301393.html
Copyright © 2011-2022 走看看