我注意到第一次运行脚本时,它比第二次和第三次运行脚本花费的时间要多得多1。这个问题中提到了"热身",但没有解释。
为什么代码在"预热"后运行得更快?
在调用2之间我没有clear all
,但是每次函数调用的输入参数都会改变。有人知道这是为什么吗?
<子>1. 我的驾照是本地的,所以这不是一个与驾照检查相关的问题。 子>
<子>2. 实际上,如果我加入clear all
,它的行为不会改变。 子>
在第一次之后运行得更快的一个原因是,许多东西只初始化一次,它们的结果被缓存并在下次重用。例如,在m端,变量可以定义为可锁定的函数中的持久变量。这也可能发生在事物的mex端。
此外,许多依赖项是在第一次加载之后加载的,并保留在内存中以供重用。这包括m函数、OOP类、Java类、mex函数等等。这既适用于内置的,也适用于用户定义的。
例如,在第一次运行脚本之前和之后发出以下命令,然后比较:
[M,X,C] = inmem('-completenames')
注意clear all
不一定清除上述所有,更不用说锁定函数了…
最后让我们不要忘记加速器的作用。不是每次调用函数时都解释m代码,而是在运行时将其编译为机器代码指令。JIT编译只在第一次调用时发生,因此理想情况下,在接下来的几次中运行对象代码的效率将克服每次运行时重新解释程序的开销。
Matlab解释。如果不预热代码,将会因为解释而不是实际算法而浪费大量时间。这会严重影响计时结果。
至少运行一次代码将使Matlab能够实际编译适当的代码段。
除了jit编译等特定于matlab的原因外,现代cpu还具有大型缓存、分支预测器等。即使在汇编语言中,预热这些也是基准测试的一个问题。
而且,更重要的是,现代cpu通常在低时钟速度下空闲,只有在几毫秒的持续负载后才跳到全速。
英特尔的Turbo功能变得更加时髦:当功率和热限制允许时,CPU可以比其可持续的最大频率运行得更快。因此,如果不小心控制这些因素,基准测试的前20秒到1分钟可能比其他时间运行得更快。
Amro和Marc没有提到的另一个问题是内存(预)分配。
如果你的脚本没有预先分配它的内存,它的第一次运行将是非常缓慢的,由于内存分配。一旦它完成了第一次迭代,所有的内存都会被分配,所以连续调用脚本会更有效率。
说明性示例
for ii = 1:1000
vec(ii) = ii; %// vec grows inside loop the first time this code is executed only
end