2024年5月25日发(作者:)
首先在VS2013, Release模式下面跑了一下C++代码,时间是208ms。基本重现了
C++部分的结果。这个速度的确不能算快。在我们推测具体原因以前,一定一定要先profile,
看看每一行所花费的时间是多少(不成熟的优化是万恶之源)。在VS里这个非常简单(要
求VS Ultimate,但一般订阅了MSDN AA的学校都有免费的VS Ultimate)。只要点一个
按钮就好了。
我们可以看到,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;
}
一个诡异的地方是这是个整数运算应该极其快,而且不应该有类型转换在里面。但是
profiler说50%的时间都在float到long的类型转换上面(注意图片右上角)。进一步检查
发现,rand_max怎么是double。改成int,结果不变,时间变成43ms,进一步提速2倍。
再profile得到: 一个诡异的地方是这是个整数运算应该极其快,而且不应该有类型转换在
里面。但是profiler说50%的时间都在float到long的类型转换上面(注意图片右上角)。
进一步检查发现,rand_max怎么是double。改成int,结果不变,时间变成43ms,进一步
提速2倍。再profile得到:
这时候我们可以看到时间非常平均,也没有明显瓶颈了。优化结束。
考虑到我们机器的不同,我的43ms大约相当于你的机器的31ms,相比于vba的570ms
有了18倍的性能差异,感觉还是比较合理的。
几点讨论:
• 其实在这个回答里,核心并不是程序优化的具体技巧,而是拿到一个问题如何思考和
利用工具的通用方法。比如即使我们不知道profiler这个东西,通过搜索"代码 每一行 时间
"也可以很快知道有这样的工具叫做profiler,并且学会怎么使用。即使不知道rand这个函
数怎么加速,通过搜索引擎也可以找到别人写好的现成代码。另一方面是发现瓶颈之后也不
要着急自己修复,如果不是特别一目了然的话,先看看别人是怎么做的。站在巨人的肩膀上,
事半功倍。所以关键在于时刻知道自己想要的是什么,和分析-调研-实验的思维习惯。
• 具体关于程序优化,我们绝大多数人没有那么牛的经验,一眼就能看出问题在哪里。
所以遇到性能问题,第一反应应当是用profiler看看瓶颈到底在哪。而且一个经验是这个瓶
颈往往是很难猜的——比如这个例子直接看代码第一反应往往是用代数和工程方法去优化
算半径的那部分。但就算这部分做到极致,rand速度提不上去,最多也只能把时间降到原
来的一半,事倍功半。以前我写代码也会在写的时候用各种奇技淫巧提升速度,但后来发现
总体上程序的速度并没有得到提升。因为程序80%的时间其实花在20%的代码里,剩下80%
的代码就算花个两个月优化到速度无穷快,也还是白瞎。所以一个兼顾开发和运行效率的方
法是,先怎么方便开发怎么写,然后用profiler找到瓶颈再有针对性地优化。
• 前两点不仅可以节省时间,可能更重要的是,如果你面对的不仅是一个工程,而且是
老板,你要说服老板你这么做的原因。这些profile的结果、别人的讨论、你自己的实验结
果,都会1) 说服老板你这么做是对的,2) 给老板留下深刻印象:你干了很多事,脑子清楚。
以后升迁啥的都有帮助。
• 上面用的是Windows平台的VS,方便好用但也非常贵。如果是Linux平台下可以用
gprof(不晓得有没有GUI版本的,望指教)。Mac下可以用XCode。但基本思路都是一样
的。
发布评论