zoukankan      html  css  js  c++  java
  • 学习笔记1:性能问题在于你想不到的任何地方!

    今天在做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?

    所以只要改成

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

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

  • 相关阅读:
    【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 15—Anomaly Detection异常检测
    【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 14—Dimensionality Reduction 降维
    【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 13—Clustering 聚类
    【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 12—Support Vector Machines 支持向量机
    【原】机器学习公开课 目录(课程笔记、测验习题答案、编程作业源码)...持续更新...
    【原】Coursera—Andrew Ng机器学习—Week 11 习题—Photo OCR
    【原】Coursera—Andrew Ng机器学习—Week 10 习题—大规模机器学习
    【原】Coursera—Andrew Ng机器学习—Week 9 习题—异常检测
    【原】Coursera—Andrew Ng机器学习—Week 8 习题—聚类 和 降维
    【原】Coursera—Andrew Ng机器学习—Week 7 习题—支持向量机SVM
  • 原文地址:https://www.cnblogs.com/blqw/p/3300420.html
Copyright © 2011-2022 走看看