C++程序度量驱动调优实例:看狄更斯的双城记,寻找性能瓶颈
作为一个专业的程序员,你写了一段程序,完成了一个功能,似乎达到了用户的要求,其实你心里也没底。
做一个简单的测试, 跑了一个主要流程,基本的功能应该是满足需求的,但是性能呢?
我们需要对程序的性能进行度量,确保性能是满足用户需求的。如果性能不理想,必需要找到瓶颈在哪里。
最近在读狄更斯的小说《双城记》英文原版,既是学习英语,也是领略大师的行文。同时,我想知道大师喜欢用什么词,所以写了一个小程序来统计这部小说的词汇。让我们度量一下这个小程序的性能,看看瓶颈在哪里, 有什么好的方法。
程序示例
需求
设计
用C++ 来写一段小程序,取名为 WordBank , 基本功能就是
- 获取总的单词数量:
getTotalWordCount();
- 获取不重复的单词总数:
getUniqueWordCount);
- 打印若干个使用频率最高的单词:
printTop(int n)
- 获取某个单词的使用频度排序号:
getWordRank(const std::string& name);
- 获取某个单词的使用数量:
getWordCount(const std::string& name);
我想看看
- 大师在这本书中使用了多少词汇
- 大师用的最多的20个单词
- "think" 这个单词用了多少次
- "think" 排在最常使用率排名的多少位
于是,我就写了一个C++ 类 WordBank, 使用 std::map<std::string, int> m_mapWords;
来保存单词的个数,使用 std::vector<std::pair<std::string, int>> m_vecWords;
来保存排过序的单词使用率排名。
#ifndef __WORD_BANK_H__
#define __WORD_BANK_H__#include <cstdint>
#include <string>
#include <map>
#include <set>
#include <vector>class WordBank
{
public:WordBank(const std::string& words_file);int getWordRank(const std::string& name) const;int getWordCount(const std::string& name) const;void sortWords();void printTop(int n) const;int getTotalWordCount() const;int getUniqueWordCount() const;private:bool hasWord(const std::string& word) const;void increaseWordCount(const std::string& word);void addWord(const std::string& word);std::map<std::string, int> m_mapWords;std::vector<std::pair<std::string, int>> m_vecWords; uint32_t m_wordCount;};std::string convertString(const std::string& word);#endif
实现
#include "WordBank.h"
#include <iostream>
#include <fstream>
#include <algorithm>using namespace std;bool comparePair(pair<string, int>& a, pair<string, int>& b)
{ return a.second > b.second;
} WordBank::WordBank(const string & words_file): m_wordCount(0) {ifstream is(words_file.data());if (!is) {throw invalid_argument("unable open file");}string word;while (is >> word) {m_wordCount ++;if (!hasWord(word)) {addWord(word);}else {increaseWordCount(word);}}
}int WordBank::getWordRank(const std::string& word) const {int count = getWordCount(word);if (count == 0) {return 0;}int rank = 1;for (const auto&[key, value] : this->m_mapWords) {if (value > count) {rank++;}}return rank;
}int WordBank::getWordCount(const std::string& word) const {string str = convertString(word.data());auto it = m_mapWords.find(str);if (it != m_mapWords.end()) {return it->second;}return 0;
}int WordBank::getTotalWordCount() const {return m_wordCount;
}int WordBank::getUniqueWordCount() const {return m_mapWords.size();
}bool WordBank::hasWord(const string & word) const {string str = convertString(word.data());auto it = m_mapWords.find(str);if (it != m_mapWords.end()) {return true;}return false;
}
void WordBank::increaseWordCount(const string & word) {string str = convertString(word.data());auto it = m_mapWords.find(str);if (it != m_mapWords.end()) {it->second++;}
}
void WordBank::addWord(const string & word) {string str = convertString(word);if (str.empty()) {return;}//cout << "insert " << word << " -> " << str << endl;m_mapWords.insert(make_pair(str, 1));
}void WordBank::sortWords() {for (auto& pair : m_mapWords ) { m_vecWords.push_back(pair); } // Sort using comparator function sort(m_vecWords.begin(), m_vecWords.end(), comparePair); } void WordBank::printTop(int n) const {for (auto pair : m_vecWords) {cout << pair.first << ": " << pair.second << endl;if (--n <= 0) {break;}}}string convertString(const string & word) {string str("");for (size_t i = 0; i < word.length(); ++i) {uint8_t ch = word[i];if(ch > 0 && ch < 255 && isalpha(ch)) {str.push_back(tolower(ch));}}return str;
}
测试
#include "WordBank.h"
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <boost/timer/timer.hpp>using namespace std;
using namespace boost::timer;int main(int argc, char *argv[])
{string word_search = "rtp";string word_file = "rfc3550.txt";int topN = 10;if (argc > 1) {word_search = argv[1];cout << "Make statistics for word count and rank: " <<convertString(word_search) << endl;} else {cout << "usage: " << argv[0] << "<search_word> <input_file> <topN>" << endl;cout << "example: " << argv[0] << " " << word_search << " " << word_file << " " << topN <<endl;}if (argc > 2) {word_file = argv[2];cout << "Read file: " << word_file << endl;}if (argc > 3) {topN = atoi(argv[3]);}try {boost::timer::auto_cpu_timer timer;WordBank wordbank(word_file);wordbank.sortWords();std::cout << "wordbank total word count: " << wordbank.getTotalWordCount() << endl;std::cout << "wordbank unique word count: " << wordbank.getUniqueWordCount() << endl;cout << word_search << "'s count=" << wordbank.getWordCount(word_search) << endl;cout << word_search << "'s rank=" << wordbank.getWordRank(word_search) << endl;cout << "--- top " << topN << " ---" << endl;wordbank.printTop(topN);} catch(const invalid_argument& e) {cerr << "Caught exeption: " <<e.what() <<endl;}return 0;}
执行结果如下, 双城记总词数为139021 ,共使用了 10984 个单词,最常使用的词是 "the", 而 “think” 这个词用了 120 次,排名 150 位。
./bin/wordbankdemo think A-Tale-of-Two-Cities.txt 20
Make statistics for word count and rank: think
Read file: A-Tale-of-Two-Cities.txt
wordbank total word count: 139021
wordbank unique word count: 10984
think's count=120
think's rank=150
--- top 20 ---
the: 8202
and: 4998
of: 4137
to: 3545
a: 2981
in: 2642
it: 2016
his: 2005
i: 1917
that: 1904
he: 1833
was: 1765
you: 1460
with: 1354
had: 1297
as: 1148
at: 1045
her: 1038
for: 973
him: 9650.079933s wall, 0.060000s user + 0.000000s system = 0.060000s CPU (75.1%)
度量性能
使用 boost 库的 auto_cpu_timer 来计时
剖析性能
使用著名的 valgrind 软件所附带的 callgrind 的剖析性能瓶颈在哪里
sudo apt install valgrind
valgrind --tool=callgrind ./bin/wordbankdemo
sudo apt-get install python3 graphviz# 在 Debian/Ubuntu 安装 python3 和 graphviz
apt-get install python3 graphviz# 在 RedHat/Fedora 安装 python3 和 graphviz
yum install python3 graphviz# 再安装 gprof2dot
pip install gprof2dot# 生成有向图
gprof2dot -f callgrind -n10 -s callgrind.out.816 > valgrind.dot
dot -Tpng valgrind.dot -o valgrind.png
从上图可以看出,其大部分时间花在 WordBank 的构造方法,其中 hasWord
, increaseWordCount
这两个方法花了大部分时间, 其中 convertString
和map 的红黑树的 find
方法又占据了大部分时间, 仔细看看这两个方法的调用,其实我们能够做出优化
WordBank::WordBank(const string & words_file): m_wordCount(0) {ifstream is(words_file.data());if (!is) {throw invalid_argument("unable open file");}string word;while (is >> word) {m_wordCount ++;if (!hasWord(word)) {addWord(word);}else {increaseWordCount(word);}}
}
- word 可以事先转化
convertString
方法不需要重复调用 hasWord
和increaseWordCount
不需要重复查找, 可以把迭代器作为额外参数传入, 或者把 map 的 value 的引用传出来
试着改一下,再重复上述的度量过程, 你能清晰地看出来改进的效果。
代码链接参见
- https://github.com/walterfan/snippets/blob/master/cpp/inc/WordBank.h
- https://github.com/walterfan/snippets/blob/master/cpp/src/WordBank.cpp
- https://github.com/walterfan/snippets/blob/master/cpp/exam/WordBankDemo.cpp
http://www.taodudu.cc/news/show-7203720.html
相关文章:
- SAT阅读:双城记材料分析
- noip模拟赛 双城记
- 【全文检索_03】Lucene 基本使用
- 《双城记》
- 双城记 A Tale of Two Cities
- 开设 AI本科专业 的国内高校一览
- 2021年全球“美食界”打卡指南整理!中国有多家餐厅、酒吧榜上有名
- AI开发之——Leonardo—Community Feed模型制作图形(4)
- 高规格国赛接棒AidLux AI应用竞赛,AidLux邀你来报名赢大奖!
- 30个网站源码
- 在线出售域名页面html源码
- 网站源码
- 如何选择连锁药店收银管理系统,推荐参考5个原则
- 连锁店电商“双私域流量”运营解决方案 F2B2b2C解决方案
- 连锁店收银系统如何帮助鞋店管理好分店?
- ss 管理系统 php 源码,基于SSM框架下的B/S服装连锁店管理系统,源码分享
- 连锁企业经营的8大成功密码
- 基于量子遗传算法的函数寻优算法—MATLAB实现
- 朋友推荐的一篇文章--寻爱
- 新站发布——寻爱交友网
- 英国留学怎么样
- 留学信息资讯
- ChatGPT这么火,对留学有什么影响?
- 国外论坛
- 傲游网络安全浏览器最新发布,四大企业结安全联盟
- 阿里钉钉,傻了
- 武汉大学科傻平差--CosaGPS(以附2.1 Example/Demo 算例)
- 【新鲜出炉】傻孩子大神关于IAP的一些闲聊
- 【平差软件学习---科傻】 一、认识和安装科傻
- 科傻使用体会
C++程序度量驱动调优实例:看狄更斯的双城记,寻找性能瓶颈相关推荐
- 智能路由心酸调优路——看推广代码简洁之道的重要性
智能路由心酸调优路--看推广代码简洁之道的重要性 甜橙金融作为一个日均订单量过千万的面向C端的互联网金融科技公司,525爆点活动订单量更是平时的好几倍,随着公司业务的高速发展,原有的系统架构,对于业务 ...
- 浅谈Spark应用程序的性能调优
浅谈Spark应用程序的性能调优 :http://geek.csdn.net/news/detail/51819 下面列出的这些API会导致Shuffle操作,是数据倾斜可能发生的关键点所在 1. ...
- 对 Web 应用程序进行性能调优
这是一位IBM专家对 Web 应用程序进行性能调优 转载于:https://www.cnblogs.com/zwh-Seeking/articles/11059351.html
- 被法拉第夸、狄更斯为她读诗、英王参加她的成人礼,程序员祖师的人生有多传奇?...
作者 | Aholiab 出品 | 程序人生 (ID:coder _life) 阿达·拉芙莱斯,一个IT圈里人人都听过的名字.被称为「程序员的开山鼻祖」,但也存在着旷日持久的争议. 探索关于Ada的一 ...
- Android性能调优实例
本文主要分享自己在appstore项目中的性能调优点,包括 同步改异步.缓存.Layout优化.数据库优化.算法优化.延迟执行等. 一.性能瓶颈点 整个页面主要由6个Page的ViewPager,每个 ...
- Oracle调优之看懂Oracle执行计划
1.文章写作前言简介 之前曾经拜读过<收获,不止sql调优>一书,此书是国内DBA写的一本很不错的调优类型的书,是一些很不错的调优经验的分享.虽然读了一遍,做了下读书笔记,觉得很有所收获, ...
- 深入浅出JVM调优,看完你就懂
深入浅出JVM调优 基本概念: JVM把内存区分为堆区(heap).栈区(stack)和方法区(method).由于本文主要讲解JVM调优,因此我们可以简单的理解为,JVM中的堆区中存放的是实际的对象 ...
- JVM解读-性能调优实例
2019独角兽企业重金招聘Python工程师标准>>> JVM性能调优 1 堆设置调优 年轻代大小选择 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选 ...
- win7查看tomcat端口_想研究Tomcat性能调优,看这篇就够了
一.下载地址 https://tomcat.apache.org/download-80.cgi 二.安装步骤 将安装包 apache-tomcat-8.5.39.tar.gz 上传至服务器 /usr ...
最新文章
- shell中竖线的作用_如何在 Linux 中安装、配置和使用 Fish Shell?
- 106:HttpResponse对象讲解
- cv2.waitKey(x)解析
- Eclipse 常用快捷键-java
- IntelliJ IDEA中日志分类显示设置
- 蒙特卡洛方法_基本理论-蒙特卡洛方法与定积分
- JQuery 方法查询大全
- 复练-关于面试的科技树-简历的提升、问答环节
- Spring框架知识要点总结(第一天)
- 乘法逆元(ex_gcd和同余定理)
- Android源码刷机步骤
- 2020年中国电力线载波通信行业发展现状及竞争格局分析,国家电网持续推进电网转型升级,配电自动化覆盖率达到90%「图」
- 中交一公局二公司全面推进章管家 印章智慧管理转型在即
- Xilinx FPGA “打一拍”“打两拍”以及IOB含义
- 遇到长GC停顿、CPU满载、内存泄露、JVM崩溃等高频问题,看这里!
- 大数据技术之Hadoop(入门)概述、运行环境搭建、运行模式
- getopt.h和getopt(),getopt_long()等函数
- Amazon DynamoDB
- 如何在手机上收发邮件?
- FreeModbus