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