【数独个人项目】性能改进

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()自身代码也可以再进行优化。

猜你喜欢

转载自blog.csdn.net/qq_37571192/article/details/85318648