【第二篇】建设网站,有什么新手程序员不知道的小技巧?

2017-12-15


当时遇到的问题是一段C++程序速度非常慢。对于这样的情况,我们需要用科学的方法和适当的工具来找到问题的原因,而不是乱猜问题在哪里,随便改。具体地说,我们用了以下的方法:

我首先在VS2013, Release模式下面跑了一下C++代码,时间是208ms。基本重现了C++部分的结果。这个速度的确不能算快。在我们推测具体原因以前,一定一定要先profile,看看每一行所花费的时间是多少(不成熟的优化是万恶之源)。在VS里这个非常简单(要求VS Ultimate,但一般订阅了MSDN AA的学校都有免费的VS Ultimate)。只要点一个按钮就好了,如下图所示。

<img src="https://pic3.zhimg.com/50/71d34991410ad65efe58982a406ceb1a_hd.jpg" data-rawwidth="557" data-rawheight="214" class="origin_image zh-lightbox-thumb" width="557" data-original="https://pic3.zhimg.com/71d34991410ad65efe58982a406ceb1a_r.jpg">

出来的结果类似:

<img src="https://pic2.zhimg.com/50/f04441f28c1e88c0cc1783e4f2630b31_hd.jpg" data-rawwidth="1181" data-rawheight="707" class="origin_image zh-lightbox-thumb" width="1181" data-original="https://pic2.zhimg.com/f04441f28c1e88c0cc1783e4f2630b31_r.jpg">

我们可以看到,rand()占用了56.3%的时间,是性能的瓶颈。此外,整数的减法也占用了33.4%的时间。
知道了原因以后就好办了。第一步,放狗搜索c++ slow rand。出来一大坨结果。其中一个是
Need a fast random generator for c++
里面提供了一个快速的rand()实现。把代码粘进去。
		
		
		
unsigned int g_seed = 0;
unsigned int fastrand() {
g_seed = (214013 * g_seed + 2531011);
return (g_seed >> 16) & 0x7FFF;
}
瞬间提速1倍到了99ms,结果不变。再profile得到:

<img src="https://pic2.zhimg.com/50/dae918da7336d0d308140c1511b9441d_hd.jpg" data-rawwidth="1178" data-rawheight="598" class="origin_image zh-lightbox-thumb" width="1178" data-original="https://pic2.zhimg.com/dae918da7336d0d308140c1511b9441d_r.jpg">

一个诡异的地方是这是个整数运算应该极其快,而且不应该有类型转换在里面。但是profiler说50%的时间都在float到long的类型转换上面(注意图片右上角)。进一步检查发现,rand_max怎么是double。改成int,结果不变,时间变成43ms,进一步提速2倍。再profile得到:

<img src="https://pic3.zhimg.com/50/a7689b020c6393a5bddc1058afe05c06_hd.jpg" data-rawwidth="1192" data-rawheight="682" class="origin_image zh-lightbox-thumb" width="1192" data-original="https://pic3.zhimg.com/a7689b020c6393a5bddc1058afe05c06_r.jpg">


这时候我们可以看到时间非常平均,也没有明显瓶颈了。优化结束。
考虑到我们机器的不同,我的43ms大约相当于你的机器的31ms,相比于vba的570ms有了18倍的性能差异,感觉还是比较合理的。
几点讨论:
  • 其实在这个回答里,核心并不是程序优化的具体技巧,而是拿到一个问题如何思考和利用工具的通用方法。比如即使我们不知道profiler这个东西,通过搜索"代码 每一行 时间"也可以很快知道有这样的工具叫做profiler,并且学会怎么使用。即使不知道rand这个函数怎么加速,通过搜索引擎也可以找到别人写好的现成代码。另一方面是发现瓶颈之后也不要着急自己修复,如果不是特别一目了然的话,先看看别人是怎么做的。站在巨人的肩膀上,事半功倍。所以关键在于时刻知道自己想要的是什么,和分析-调研-实验的思维习惯。
  • 具体关于程序优化,我们绝大多数人没有那么牛的经验,一眼就能看出问题在哪里。所以遇到性能问题,第一反应应当是用profiler看看瓶颈到底在哪。而且一个经验是这个瓶颈往往是很难猜的——比如这个例子直接看代码第一反应往往是用代数和工程方法去优化算半径的那部分。但就算这部分做到极致,rand速度提不上去,最多也只能把时间降到原来的一半,事倍功半。以前我写代码也会在写的时候用各种奇技淫巧提升速度,但后来发现总体上程序的速度并没有得到提升。因为程序80%的时间其实花在20%的代码里,剩下80%的代码就算花个两个月优化到速度无穷快,也还是白瞎。所以一个兼顾开发和运行效率的方法是,先怎么方便开发怎么写,然后用profiler找到瓶颈再有针对性地优化。
  • 前两点不仅可以节省时间,可能更重要的是,如果你面对的不仅是一个工程,而且是老板,你要说服老板你这么做的原因。这些profile的结果、别人的讨论、你自己的实验结果,都会1) 说服老板你这么做是对的,2) 给老板留下深刻印象:你干了很多事,脑子清楚。以后升迁啥的都有帮助。
  • 不懂的问题上知乎问!这也是非常重要的一部分。
  • 上面用的是Windows平台的VS,方便好用但也非常贵。如果是Linux平台下可以用gprof(不晓得有没有GUI版本的,望指教)。Mac下可以用XCode。但基本思路都是一样的。



作者:grapeot

链接:https://www.zhihu.com/question/36426051/answer/83334589
来源:知乎


合作意向申请

如果您的企业需要制作网站,请留下您的联系方式,我们会为您提供良好的服务!

联系方式

021-50110509

18621585859(同微信号)

lewebsite@leadin.cn

上海陆家嘴“左岸88创意园”B402室 (北张家浜路88号)

WEB商学院

网站百科

专家百科

公众微信号

上海领意文化传播有限公司版权所有 © 2006-2018 LEADIN MEDIA 沪ICP备10205459号-6

@领意微品牌 网站设计服务顾问