我最近使用進程外會話狀態對ASP.NET應用程序進行了一些性能測試和分析 - 在Web場中使用會話狀態時這是必需的,以便可以檢索狀態任何Web服務器,例如如果隨後的HTTP請求到達不同的服務器,因爲會話不「粘」或原始服務器宕機等等。糟糕的序列化性能的可能解決方案
令我驚訝的是,當我以滿負荷運行Web服務器並分析CPU使用率例如99%的CPU時間花在序列化和反序列化會話狀態上。隨後我們實現了一個定製的'緩存'狀態服務器;這總是序列化狀態,但也保持狀態在內存中,所以如果你使用粘性會話狀態不必大部分時間反序列化。這將服務器吞吐量提高了2倍;但是,序列化仍佔CPU時間的98%或更多。
我們通過在序列化之前「修剪」會話狀態中對象之間不必要的對象引用,進一步提高了速度 - 在序列化之後手動修復了引用。這又提高了10-20%左右的速度。這裏的推理是一些性能損失是由於內置的序列化不得不遍歷對象指針的圖形,這隨着更多指針而變成更復雜的任務。
繼續調查,我們爲我們的一些類編寫了定製的序列化例程,而不是依賴.Net的內置序列化。我們發現的性能是大大提高了,減少了約50x。看起來大部分的CPU負載是由內置的.Net序列化引起的,由於依賴於使用反射來遍歷對象指針/圖形和提取字段數據,反過來又很慢。
將網絡服務器的硬件要求降低一個很大的因素(功耗要求較低但仍然很重要),這非常有吸引力,可以將我們的性能提高50倍。目前的選項是:
1)編寫定製的序列化。由於任務的複雜性和它產生的維護開銷,這是一個問題,也就是說,對類狀態的任何改變都需要改變序列化/反序列化例程。
2)一些第三方解決方案。也許有些產品會在構建時自動生成狀態保存/加載代碼,從而無需使用Reflection。
我很想知道是否有人知道第三方解決方案,或者遇到過這個問題,因爲我從互聯網搜索中沒有發現任何提及。
更新: 有些人建議在默認的內置序列化和純定製序列化例程之間的一種中途解決方案。這個想法是,你可以爲最能影響性能的類實現自定義序列化,例如, Overiding ISerializable。這是一個有趣而有前途的方法;但是我仍然認爲有一個完全替代內置序列化的空間,而不必編寫和維護任何自定義代碼 - 這不能在運行時完成,因爲需要Reflection來查詢對象並訪問私有數據。但理論上可以對已經構建的程序集進行後處理,並將其作爲額外的構建步驟注入新的方法。一些分析器使用這種方法在C#編譯器構建完成後將分析代碼注入到程序集中。另外我/我想/我在某處閱讀.Net框架支持向類中注入方法 - 因此所有與IL有關的混亂都可能被處理。
很確定你所說的注入方法是使用部分類。我認爲這個原則是,如果同一個名字空間中的兩個類具有相同的名稱並且一個名稱被標記爲部分。一個DLL是由兩個類的方法和屬性組合而成的。 – Robert 2010-01-26 08:38:44