Pat*_*ick 5 performance matlab
这个错误是由于Matlab太聪明了.
我有类似的东西
for k=1:N
stats = subfun(E,k,stats);
end
Run Code Online (Sandbox Code Playgroud)
其中stats
是一个1xN
阵列,N=5000
比方说,和subfun
计算stats(k)
从E
,并且它填充到统计
function stats = subfun(E,k,stats)
s = mean(E);
stats(k) = s;
end
Run Code Online (Sandbox Code Playgroud)
当然,来回传递大数组会有一些开销,只是为了填充其中一个元素.然而,在我的情况下,开销是可以忽略的,我更喜欢这个代码而不是
for k=1:N
s = subfun(E,k);
stats(k) = s;
end
Run Code Online (Sandbox Code Playgroud)
我的偏好是因为我实际上有更多的任务而不仅仅是stats
.此外,一些任务实际上更复杂.
如上所述,开销可以忽略不计.但是,如果我做一些微不足道的事情,比如这个无关紧要的if语句
for k=1:N
i = k;
if i>=1
stats = subfun(E,i,stats);
end
end
Run Code Online (Sandbox Code Playgroud)
然后,在subfun内发生的任务突然变为"永远"(它比N线性地增加得快得多).这是任务,而不是永远的计算.事实上,它甚至比以下荒谬更糟糕subfun
function stats = subfun(E,k,stats)
s = calculation_on_E(E);
clear stats
stats(k) = s;
end
Run Code Online (Sandbox Code Playgroud)
这需要每次重新分配统计数据.
有没有人知道为什么会这样?
这可能是由于Matlab的JIT的一些模糊细节.最近版本的Matlab的JIT知道不创建新数组,而是在某些有限的情况下进行就地修改.其中一个要求是将函数定义为
function x = modify_big_matrix(x, i, j)
x(i, j) = 123;
Run Code Online (Sandbox Code Playgroud)
而不是
function x_out = modify_big_matrix(x_in, i, j)
x_out = x_in;
x_out(i, j) = 123;
Run Code Online (Sandbox Code Playgroud)
您的示例似乎遵循此规则,因此,正如Praetorian所提到的,您的if
声明可能会阻止JIT识别它是一个就地操作.
如果您确实需要加速算法,可以使用自己的mex函数就地修改数组.我已经成功地使用这个技巧在一些中等大小的阵列上获得了4倍的加速(订购100x100x100 IIRC).但是不建议这样做,如果你不小心可能会在某些版本中停止工作.
正如其他人所讨论的,问题几乎肯定在于 JIT 及其相对脆弱的就地修改能力。
如前所述,我确实更喜欢函数调用和赋值的第一种形式,尽管已经建议了其他可行的解决方案。在不依赖 JIT 的情况下,唯一有效的方法(据我所知)是某种形式的引用传递。
因此,我创建了一个Stats
继承自handle的类,其中包含k=1:N
. 然后通过引用传递它。
为了将来的参考,这似乎工作得很好,具有良好的性能,我目前正在使用它作为我的工作解决方案。