第三周-词频统计效能分析

效能分析作业具体要求如下:https://edu.cnblogs.com/campus/nenu/SWE2017FALL/homework/956

这篇博客由如下几个方面进行阐述:

1.预备工作

2.性能分析

3.优化修改

4.学习总结

一.预备工作

git地址:https://coding.net/u/huyr000/p/countWords/git

1.要求:重定向由文件系统读入,连续三次运行结果

三次运行结果截图:

三次平均运行时间大概在5.7s左右,CPU占用20%~40%。

2.我猜测程序的瓶颈代码段如下

 rline = rline.ToLower();

之所以认为此处是瓶颈,是因为曾经看过一篇文章,说一般语言自带的函数会比自己定义的函数慢一点,如果自己定义一个优化的大写转小写函数应该快一点。

预计优化后会运行时间会少一秒左右。

二.性能分析

      我使用的是vs自带性能分析工具Profiler,主要用来提升性能和寻找瓶颈。在主菜单中的调试选项中,就会有对应的性能分析的选项。如果你发现没有这个选项,那么,你需要安装一个更为强大的VisualStudio版本,Team系列的VS才会有这个工具的安装。

      Profiler很强大,你可以用它分析一个二进制文件,可以用它分析一个工程,也可以用它分析一个网站。无论是C#、VC还是VB,它能很好的分析。你可以用Profiler对一个Target做很多事情。最重要的当属函数执行时间的分析,Profiler会给出函数的执行时间,执行次数,执行时间占整个程序的百分比;更强大的是,他可以给出一个调用树,这样,你可以在Profiler中查看这个程序到底是如何被一步步调用的。查看的过程中,你还能看到这些函数的执行百分比,你可以非常方便的找到最耗时的函数。一层层的查下去,原来瓶颈就是那个你可能都没有正眼看过的小函数。感谢Profiler,你可以有目的的优化你的程序了。优化以后,你总得看看效果吧,于是再利用Profiler进行分析,然后呢?Profiler提供结果比较功能,很好很强大。你可以通过这个功能看看你的程序,哪些函数的执行效率提升了,哪些又降低了。很方便。

我使用vs2010自带的性能分析工具时:

自带的性能分析工具包含如下四个方面的内容:

进行下一步的时候出现了这个问题:

解决方案:要在/standalone Profiler路径下安装vs_profiler.exe,因为我在安装的时候没有standalone Profiler目录,并且vs2010没有提供实现重定向的一个属性IsInputRedirected,所以就重装vs2015版本。vs下载链接[http://down.nenu.edu.cn/]

vs2015版本相对于vs2010版本,多了几个功能。CPU使用率,GPU使用情况,内存使用率

当点击性能向导时,便出现了vs2010版本的4项分析

第一次分析结果

CPU使用百分率

CPU运行时间和进程内存的分析

GPU使用情况

调用函数分析

函数占用比的分析

代码的分析

三.优化修改

1.修改一

某个方法实现所包含的代码路径可能导致对同一对象多次调用Dispose 等效的方法(例如,用于某些类型的 Close() 方法)。正确实现的 Dispose方法可以调用多次,而不会引发异常。 然而,这是无法保证的。为避免生成 System.ObjectDisposedException,不应对一个对象调用 Dispose 多次。

需优化代码块:

 private static string ReadFile(string file)
        {
            string rline;
            FileStream fs = new FileStream(file, FileMode.Open);
            StreamReader sr = new StreamReader(fs);
            rline = sr.ReadToEnd();
            sr.Close();
            fs.Close();
            return rline;
        }

解决方法:使用 try/finally 块,在 finally 块中,确保 stream 资源不为 null。

更改后代码如下:

 private static string ReadFile(string file)
        {
            try
            {
                string rline = null;
                FileStream fs = new FileStream(file, FileMode.Open);
                StreamReader sr = new StreamReader(fs);
                rline = sr.ReadToEnd();
                return rline;
            }
            finally
            {
                if (sr != null && fs != null)
                {
                    sr.Dispose();
                    fs.Dispose();
                }
            }
}

最终改为:

//获取控制台重定向文件数据流
                    StreamReader ioIn = null;
                    ioIn = new StreamReader(Console.OpenStandardInput());
                    string rline;
                    rline = ioIn.ReadToEnd();

2.修改二

根据profile分析的结果,System.Object.Equals(object)函数消耗时间较多。

需优化代码:

 if (args.Length >0 &&args.Equals("-s"))

C#中常见的比较字符串的方法有Compare、CompareTo、Equals、==方法。后来随便写了个程序用三种方法比较两个简单的字符串,得出的结论是直接用“==”最快

更改后的代码如下:

 if (args.Length >0 && args[0] == "-s")

3.修改三

需优化代码:

rline = rline.ToLower();

写了一个自己定义的大写转小写的函数

public static StringBuilder ToLower(StringBuilder str) 
        {
            for (int i = 0; i < str.Length; i++) 
            {
                if (str[i] <= 'Z') 
                {
                    str[i] =(char) ((int)str[i]+32);
                }
            }
                return str;
        }

调用变为:

rline = ToLower(rline);

最终优化后运行截图:

运行时间由5s多变为0.5s多了呢,开心

用老师推荐的ptime.exe测试时间截图如下:

通过优化之后,发现运行时间变少,与其他同学的程序结果对同一war_and_peace.txt比较,发现单词的总量和每个单词出现的总数类似(相差度不超过十),精确度变高了。优化之前的单词总量和词频都是有错的。

再次profile得到的结果如下:

CPU使用百分率:

函数占用比:

为什么会这样呢?

为什么只能分析一个工作函数?

然后我使用另外一种方法再次测试,用.exe文件进行测试,具体操作如下:

然后进行分析,得到了报错,不支持IO重定向测试。

这时候我又在想为什么我能得到优化前的equals()函数占用比,那时候也是不支持IO重定向的呀。然后又对以前的代码进行测试,发现能得到以前的equals()函数的占用比,是因为先前的代码并没有持续进行,只能探测到equals()就被暂停了。

因为无法进行重定向,想办法解决,解决方案:在调试选项中选择wf属性,然后再进行profile。

具体操作如下:调试 -> wf属性 ->命令行参数设定如下

函数执行占比如下:

优化前最花费时间的3个函数为正则,分割字符串,哈希表。

因为优化后运行时间少于1s,所以我挂起了2s。此时运行截图为:

注意点:当优化后的运行时间如果少于1s(秒级),就得不到分析结果,如果你优化后程序运行时间少于1s左右,此时你就可以用sleep()函数,可以让它挂起1000ms以上,再测试就会有分析结果出现了。

再一次profile:

优化后最花费时间的函数:正则,分割字符串,哈希表,IO流。

四.学习总结

       通过这次对程序进行效能分析,知道了效能分析的大致流程。实践第一步是要确保编译的程序是Release版本,然后在visual studio界面中选中Tools | Performance Tools | Performance Wizard,先用抽样的方法找到效能瓶颈所在,然后对特定的模块用代码注入的方法进行详细分析。在效能分析过程中要一直反复进行“效能测试,分析,改进,再效能测试”的流程,才能逐渐提高程序的效能和我们的编程水平。也要避免没有做分析就过早进行优化,“过早优化是万恶之源”。如果我们不经分析就盲目优化,也许只能达到事倍功半的效果。

原文地址:https://www.cnblogs.com/huyourongmonkey/p/7581219.html