软件工程第2次作业—效能分析

作业要求的博客链接:https://edu.cnblogs.com/campus/nenu/2016CS/homework/2139

git仓库地址:https://git.coding.net/isak_even/wfAnalysis.git

第一次作业—词频统计v1.0:https://www.cnblogs.com/kongwy/p/9662364.html

一、项目概要:

  本次项目实现的是词频统计的效能优化,v1.1主要改进功能三,目前测试《战争与和平》结果的最优时间为0.385。

二、效能分析

1.以war_and_peace.txt作为测试文件,连续三次运行,给出每次消耗时间。

原始代码没有使用命令行参数,经过改进后测试截图如下:

2.猜测瓶颈

 (1)第一个瓶颈应该就是读文件,将文本处理成字符串。这次处理的是3.14MB的文本文件,读文件一定是耗时最长的单元,这个地方应该优化一下。估计优化后时间会缩短一半。

/* ----实现读取指定文件的功能-----*/
void readtxt(string filename)
{
    ifstream file;
    file.open(filename.c_str());//注意一定要转化为 char *
    string s;        //每次读取一行txt文件返回的字符串
    while(getline(file, s))//按行读取
    {
        str=s+' '+str;//加空格确保分割开行尾和行首的两个单词
    }
    transform(str.begin(), str.end(), str.begin(), ::tolower);//将大写转化为小写
    file.close();    //关闭文件
}

 (2)第二个是分割字符串,并且统计合法单词的词频。理由同上,测试数据过大所以耗时长,优化后时间会缩短。

for (long i=0;i<str.length();i++)
    {
        while(str[i]>='0'&&str[i]<='9'||str[i]>='a'&&str[i]<='z')
        {
            temp=true;
            b+=str[i];
            i++;
        }
        if(temp)
        {
            word=b;
            if(word[0]>'9'||word[0]<'0') //判断第一个字符是不是数字
            {
                ++word_count[word];
                vec.push_back(word);
            }

            b="";
            word="";
            temp=false;
        }
    }

3.利用profile找出瓶颈并优化

 第一次profile的截图如下:

 (1)可以看出getline(file,s)和字符串的合并是耗时最长的。分析后决定把读文件和分割出合法字符串合在一起,读完一行就进行处理,就可以省略str = s+' '+str。

 (2)调试后发现transform函数也比较耗时,便将处理大小写转变为判断字符,确定是大写字母再转化为小写字母。

 (3) 将for (long i = 0; i<str.length(); i++) 转变为 long a = str.length();  for (long i = 0; i<a; i++),这样不需要每次循环都调用length()函数。

优化后第二次profile截图如下

 (1)再次测试后此时耗时最长的是b=b+str[i]。参考博客:http://www.cnblogs.com/chuncn/archive/2009/02/13/1390176.html 我改为:b.append(1,str[i]);

 (2)++word_count[word]耗时也长。map函数是自动排序的,这样效率会低一点,所以我换成unordered_map<string, long> word_count;

参考博客:http://www.cnblogs.com/me115/archive/2013/06/05/3117967.html

(3)最后将功能一和二共同改进一下。

4.优化后的profile截图

5.优化后时间

三、自我评估

个人基本情况见第零次作业 博客地址:https://www.cnblogs.com/kongwy/p/9611339.html

这次作业主要是优化代码,提高效率,也是解决自己上次遗留的问题。

(1)在初步测试的时候其实不太好用,通过参考其他人的博客,发现没有使用命令行参数,就是int main(int argc, char* argv[]),更改之后代码也简单了不少。

(2)用ptime测试时发现电脑配置对代码的运行效率影响较大,所以在室友的笔记本和学院的机房都进行了多次测试。

(3)安装VS,并且启用性能分析,通过阅读《构建之法》第二章基本了解到抽样和代码注入的区别。这次采用的主要还是抽样。

(4)发现VS要求比较严格,代码不能用头文件#include<bits/stdc++.h>以及需要将 sscanf改为sscanf_s。

(5)优化代码之后大概减少了四十行,速度提高了十倍左右。

原文地址:https://www.cnblogs.com/kongwy/p/9721197.html