1. 程式人生 > >程式設計師羽化之路--假如需要一百萬個物件

程式設計師羽化之路--假如需要一百萬個物件

![image](https://bdn.135editor.com/files/users/553/5534532/202003/byhA6fOj_BGxN.png) ### 設計背景 每個平臺都會有使用者這種基礎資料的設計,作為最基礎的使用者,每個使用者都有很多屬性,比如性別,姓名,手機號等,每個使用者還可以有類似經驗值這樣的榮譽系統,根據不同的經驗值來對應不同的等級,不同的等級對應不同的榮譽UI,比如一級使用者可能只顯示一個星星,二級使用者顯示兩顆星星,以此類推,類似於QQ等級的星星月亮太陽,這樣的榮譽系統隨著平臺的不斷壯大,可能會衍生出很多型別。那麼問題來了,使用者登入的時候就需要初始化使用者的這些榮譽值,以星星數為例,類似於以下程式碼 ``` public class Star { //等級 public int Level{get ;set ;} //對應的星星數目 public int StarNumber{get ;set ;} //對應的星星顏色 public int Color{get ;set ;} ... 其他屬性 } //使用者資訊 public class User{ public Star StarInfo{get ;set ;} //...使用者的其他屬性 } //初始化使用者資訊 User u=new User(){ StarInfo=new Star(){ Level=1, StarNumber=1,Color=1}}; ``` 每一個登入使用者都會初始化一個Star屬性來表示當前使用者的Star資訊,當有100萬用戶甚至更多使用者同時線上的時候,記憶體中就例項化了同樣數量的Star物件,以及其他類似的屬性物件。這麼多重複的物件難道不能優化嗎?當然不是!! ### 問題分析 一個業務出現問題,首先要分析問題的所在。根據以上所說,問題的根本在於產生了大量的物件,首先每個使用者物件都有自己獨特的狀態,這個基本上不可能分解優化,但是類似Star這樣的屬性就有優化途徑了,這些榮譽屬性一個最大的共同點就是不可變,換句話說,等級1的使用者對應的Star資訊是永遠不會變的,永遠是level=1,starnumber=1,color=1 等。基於這個不變性,我們可以把這個Star抽離出來,供所有等級1的使用者使用,假設原來有10萬等級1的使用者,原來需要10萬個物件,現在只需要一個物件,這可是天壤之別。 ### 解決問題 基於以上問題分析,我們需要做的是把物件重複使用,只要是物件重複問題,基本上可以利用一個物件出口來解決問題,類似於以下的物件初始化工廠,但是要注意執行緒安全問題,因為同時請求並初始化物件的執行緒會有多個。 ``` public class UserStarFac { static object objLock = new object(); static Dictionary UserStarMap = new Dictionary(); public static Star GetUserStar(int level) { //利用鎖來防止例項化多次,當然這裡可以優化 lock (objLock) { Star info = null; ; if(!UserStarMap.TryGetValue(level, out info)) { info = new Star() { Color = 1, Level = 1, StarNumber = 1 }; UserStarMap.Add(level,info); } return info; } } } ``` 編寫簡單測試程式 ``` static void Main(string[] args) { int i = 0; List userList = new List(); while (i < 100000) { // userList.Add(new User() { StarInfo=new Star() { Color=1, Level=1, StarNumber=1} }); userList.Add(new User() { StarInfo= UserStarFac .GetUserStar(1)}); i++; } Console.WriteLine("初始化完成"); Console.Read(); } ``` 記憶體的測試結果: >
不執行任何程式:佔用記憶體:2.8 M >無優化初始化10萬物件:佔用記憶體:11 M >優化之後初始化10萬物件:佔用記憶體:7 M 居然一個小小的優化就減少了4M記憶體,不要小看這小小的4M,你要看的是比例,居然減少了將近 50%,真實業務中,可以進行這種優化的地方數不勝數,不知道你是否在乎呢? 這種大量重複物件的問題尤其是在遊戲程式設計中經常存在,比如五子棋遊戲,棋子的初始化,一個遊戲大廳存在成千上百萬對局,如果每個局中的棋子都初始化一個物件,那記憶體使用是相當可怕的,這種需要把通用的物件屬性,不變的物件屬性抽離出來,做共享是有必要的。 >據說這種優化有一個學名:享元模式,沒有必要記住名字,但需要記住原理和場景,必須要提一句:注意不變的物件才可以哦