首页 > 技术文章 > 20180925-3 效能分析

94V587 2018-10-08 16:30 原文

此作业的要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2145

程序地址:https://git.coding.net/tianl364/count_words.git

对上周作业中的功能4 (仅由文件重定向读入,不由控制台读入) 做效能分析,以[https://coding.net/u/younggift/p/word_count_demo/git/blob/master/war_and_peace.txt]为输入数据。

 

要求0 以 战争与和平 作为输入文件,重读向由文件系统读入。连续三次运行,给出每次消耗时间、CPU参数。

进入文件所在目录,打开控制台,输入:

1 ptime wf -s < war_and_peace.txt

连续三次运行结果如下:

 

消耗时间汇总:

第一次运行时间 0.659 s
第二次运行时间 0.507 s
第三次运行时间 0.510 s
平均时间 0.559 s

 

 

 

 

CPU参数: Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz 2.50GHz

 

要求1 给出你猜测程序的瓶颈。你认为优化会有最佳效果,或者在上周在此处做过优化 (或考虑到优化,因此更差的代码没有写出) 。

猜测的瓶颈:使用正则表达式来区分会增加程序的运行时间。

优化思路:通过枚举分割单词的各种符号,然后依次使用replace()方法进行替换。

 

要求2 通过 profile 找出程序的瓶颈。给出程序运行中最花费时间的3个函数(或代码片断)。要求包括截图。

使用命令行进入程序所在目录后输入以下命令:

1 python -m cProfile -s time wf.py -s < war_and_peace.txt

得到分析结果截图:

 

ncalls:表示函数调用的次数;

tottime:表示指定函数的总的运行时间,除掉函数中调用子函数的运行时间;

percall:(第一个percall)等于 tottime/ncalls;

cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间;

percall:(第二个percall)即函数运行一次的平均时间,等于 cumtime/ncalls;

filename:lineno(function):每个函数调用的具体信息;

 

由测试结果可知程序运行中最花费时间的3个函数及运行时间和次数:

函数 调用次数 运行时间
main() 1 0.327
getCountByPurText() 1 0.283
split() 1 0.058

 

 

 

 

 

要求3 根据瓶颈,"尽力而为"地优化程序性能。

通过对getCountByPurText()方法中去掉特殊符号方式的变化来进行优化,由之前使用正则表达式的方式换成对分割单词的各种符号进行枚举,然后依次使用replace()方法进行替换。之前使用正则表达式的代码如下:

 1 def getCountByPurText(testtext):
 2     testtext = re.sub('[^a-zA-Z0-9n]', ' ', testtext)
 3     
 4     #定义词频字典 
 5     frequency = {} 
 6 
 7     #循环判定每个单词频率
 8     for word in testtext.split(): 
 9         if word in frequency:
10             frequency[word] += 1
11         else:
12             frequency[word] = 1
13     frequency = sorted(frequency.items(),key = lambda x:x[1],reverse = True)

改成使用replace()方法后的代码如下:

 1 def getCountByPurText(inputText):
 2     inputText = inputText.lower()
 3 
 4     for disCh in '!.",)—(#:\n':
 5         inputText = inputText.replace(disCh, ' ')
 6 
 7     # 定义词频字典
 8     frequencyDic = {}
 9 
10     for word in inputText.split():
11         if word in frequencyDic:
12             frequencyDic[word] += 1
13         else:
14             frequencyDic[word] = 1
15 
16     # 根据字典的value值排序
17     frequencyDic = sorted(frequencyDic.items(), key=lambda x: x[1],
18                           reverse=True)

 

要求4 再次 profile,给出在 要求1 中的最花费时间的3个函数此时的花费。要求包括截图。

修改后再次profie:

再次测试三次运行时间截图为:

 

消耗时间再次汇总:

第一次运行时间 0.447 s
第二次运行时间 0.455 s
第三次运行时间 0.467 s
平均运行时间 0.456 s

 

 

 

 

相比之前的0.559 (s) 节省了 0.103 (s)

 

要求5 程序运行时间。根据在教师的机器 (Windows8.1) 上运行的速度排名,分为3档。此题得分,第1档20分, 第2档10分,第3档5分。功能测试不能通过的,0分。

程序地址:https://git.coding.net/tianl364/count_words.git

推荐阅读