1. 程式人生 > >【數獨個人專案】效能改進

【數獨個人專案】效能改進

github地址:https://github.com/Duuang/Project-Sudoku

日期:2018-12-26

6. 效能分析:

1. 記憶體分析

取的是生成10萬個數獨的情況,可見記憶體正常,無記憶體洩露等問題

 

2. 函式時間佔比分析、函式計時

                                                                                圖1

    取的生成10萬個數獨的情況來做效能分析,如圖1。可以看出來,從獨佔時間來看,51%的獨佔時間花在了strcat()函式上,還有35%的時間花在了Generate()函式中自己的程式碼的部分。

所以從兩方面優化:

1. 優化strcat(),查了一下,strcat的工作過程大概是:

char *strcat(char *dest, const char *src)

{

       char *tmp = dest;

       while (*dest) dest++;

       while ((*dest++ = *src++) != '/0');

       return tmp;

}

        可見,strcat呼叫時,先移動目標字串的指標到其尾部,再進行復制。這種做法對於下標比較大的陣列重複呼叫時,效率比較低。

        我之前用strcat是用在向outputstring[1005]的緩衝區來寫要輸出的一個數獨的字串,每增加一個數獨中的數字,就需要strcat一次,在後面附加上新新增的數字。

        所以為了優化浪費在這部分的時間,我放棄了使用strcat()函式,而是用一個指向當前位置的指標char *currentpos來操作字串緩衝區。每當往緩衝區寫字元時,只要用*(currentpos++) = char_to_append; 就可以向緩衝區新增字元,然後在解下一個數獨時需要清空緩衝區(將指標置到緩衝區開頭currentpos = outputstring)

        這樣的話,就已經把數獨字元寫入緩衝區的時間基本最小化了,避免了之前strcat浪費的很多時間。

 

2. 優化SudokuSolution::Generate()自身程式碼部分

       這個成員函式的自身程式碼部分(除了strcat、fwrite之類),耗費了整個程式35%的時間,也有可優化的空間。經檢查,發現了一處可優化的地方:之前,我把初始化緩衝區的語句memset(outputstring, 0, sizeof(outputstring)); 寫到了每個數獨的迴圈開始,也就是說10萬個數獨的話要清空10萬次緩衝區,緩衝區又有1000的長度,所以還是花了挺多時間用來清空緩衝區。

        然而outputstring[1005]用來做緩衝區的話,完全沒必要進行初始化工作。。是否初始化不會影響最後結果。所以去掉了初始化的語句,Generate()函式自身程式碼部分時間也就得到了優化。

 

3. 優化效果:

                                                                             圖2

      經過這兩處優化,如圖2

 1.      從整體時間來看,執行時間從原先的2.932秒,提高到了現在的0.183秒。效能為原先的16倍。

 2.      再看時間佔比,優化後在Generate()中fwrite()的函式已經佔到了Generate()函式中的70%時間。

       之前,Generate()中除了fwrite()的部分,佔到了51%(strcat)+35%(函式自身程式碼)的時間;而經過優化之後,Generate()中函式自身程式碼(包括了之前的strcat+函式自身程式碼),從原先的86%時間佔比,優化到了現在的僅有17%時間佔比。所以說這部分程式碼的時間大大降低了。

 

4. 後續可能的優化:

      現在來看,後續優化的話就主要是需要對fwrite函式進行優化的考慮了。但是這畢竟是系統函式,所以說可以換另一個更快的讀寫函式,或者自己試著實現一個更快的寫檔案函式即可。

      或者可以增大緩衝區,減少fwrite()的呼叫次數。比如10個數獨輸出一次,或者100個數獨輸出一次。本質上是用空間來換時間。。

      另外Generate()自身程式碼也可以再進行優化。