學習筆記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?

所以只要改成

這樣就沒問題了.....

 

好吧好吧  我錯怪三元表達式了,三元兄對不起啦~~~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM