C# 大型電商項目性能優化(一)


經過幾個月的忙碌,我廠最近的電商平台項目終於上線,期間遇到的問題以及解決方案,也可以拿來和大家多做交流了。

我廠的項目大多采用C#.net,使用逐漸發展並流行起來的EF(Entity Framework)框架,並搭配使用丹麥的一款主打CMS, DMS的.net web應用程序sitecore。

本篇為基礎篇,側重於闡述編碼規范和一些編碼技巧對系統性能的影響。不規范的編碼方式,可能對單個方法或模塊產生的性能影響是微不足道的,但在大型電商項目中,高並發的場景隨處可見,欠妥的編碼方式,可能會對整個系統的性能及用戶體驗,造成很大的影響。

作為電商項目,對性能影響最明顯的模塊,莫過於下訂單及修改庫存。在高並發場景下,這些模塊的數據庫存取的性能要求是非常高的,少許的性能浪費,都可能使系統在使用中的表現差強人意。

首先,我們來闡述一下EF框架下得編碼規范。這里我們可以參考msdn關於IQueryable<T>及IEnumerable<T>的介紹:

對於在內存中集合上運行的方法(即擴展 IEnumerable< T> 的那些方法),返回的可枚舉對象將捕獲傳遞到方法的參數。在枚舉該對象時,將使用查詢運算符的邏輯,並返回查詢結果。

與之相反,擴展 IQueryable <T> 的方法不會實現任何查詢行為,但會生成一個表示要執行的查詢的表達式樹。查詢處理由源 IQueryable<T> 對象處理。

 

IQueryable<T>會生成一個查詢表達式樹,並不會將數據直接取出來,但該對象的擴展方法為我們提供了大量的高效輔助功能,例如判斷數據是否存在的Any(),查詢數據數量的Count(),統計計數屬性的Sum()等,EF會幫助我們生成最優的sql,以減少數據庫存取時的性能損耗。這些方法,我們都可以用比較笨拙的編碼方式進行實現,但其效率會低很多。

另外,編碼過程中應盡可能避免使用ToList()方法及GetById()方法,這里依舊可以參考msdn,但筆者可以直白地去描述:采用這兩種方法后,程序會直接將數據從數據庫中讀取出來,並加載到內存,接下來我們可以直接操作這些實實在在的數據,並使用List<T>所擴展的方法。然而這種方案會造成以下性能問題:

1.將未經業務處理的表達式樹直接用來查詢數據,其數據量太大,數據庫的存取,磁盤的IO,都需要消耗大量的時間和空間。

2.EF支持的導航屬性,會將相關聯的對象都查出來,屆時龐大的數據又擁有更龐大的分支,讓內存和CPU飆升。

為了避免上述問題,EF為我們提供了行之有效的方法:

1.查詢初期少用ToList()及GetDtoById()方法。

2.查詢過程中,使用Select()和SelectMany()方法,只選取自己所需要的屬性或對象。

 

為了看出不規范的編碼方式帶來的性能損耗,我們來看一段例子比較:

1.以下是只選取自己所需的屬性的代碼:

var productSKU = unitOfWork.ProductSku.Get(p => p.Id == item.SKUId)
  .Select(p => new { p.Id, p.ProductId, p.Product })
  .FirstOrDefault();

提交訂單耗時的截圖:

2.采用GetById()方法:

var productSKU = unitOfWork.ProductSku.GetByID(item.SKUId);

提交訂單耗時截圖:

筆者電腦老舊,該數據在i5 8G ram的計算機中僅需要200ms的時長,在性能更強的服務器上耗時更短。

從對比中我們可以看到:僅僅只修改了一個方法,程序請求的耗時竟有將近一倍的誤差!如果我們的代碼中充斥着這種懶惰的不規范寫法,在高並發場景下,系統會被拖得很慢,甚至會出現程序報錯。

 

接下來,我們說下拋開EF框架的做法,擅長sql編程的園友,可能會不屑EF的提供的各種方案,直接寫sql,采用ADO不是更快嗎?的確,直接運行sql會讓程序更快,ADO的速度是大家所認可的。EF也支持大家使用直接編寫sql的方式:

var productSKU = dbContext.Database.SqlQuery<ProductSku>(sqlStr);

如果sql編程功力深厚,筆者是非常支持這種編程方案的。但EF框架也有其天生的優勢:

1.EF框架讓更多的初級軟件從業者更快地學習和編寫程序

2.EF提供的完善的擴展方法,幫助軟件從業人員實現各種功能

3.規范編寫的EF C#代碼,並不會比原生的sql慢太多

 

這讓筆者想起C#.net與Java程序員之間的矛盾^_^。筆者因為機緣巧合,也寫過一段時間的Java。

二者的設計理念確實有所不同:

1.C#.net讓初學者更快地入門,提供了更多的類庫和方法,其出色的IDE讓編程人員省心省力。且C#.net已經開源。

2.Java則需要編程人員做更多的思考,自己配置環境變量,自己敲命令行,讓編程人員在思考的過程中加深對計算機原理、操作系統和軟件工程的認識。

毫無疑問:兩者都是當代最出色的高級程序語言(PHP,Python,JavaScript等的同行勿噴^_^)與其花時間爭論誰才是最好的語言,不如兼而學之。

以上是本次性能優化介紹的基礎篇,后續會為大家帶來數據庫層面的優化經驗及體會。


免責聲明!

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



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