学习笔记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?

所以只要改成

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

 

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

 

posted @ 2013-09-04 10:06  冰麟轻武  阅读(2549)  评论(20编辑  收藏  举报