5

这个错误是由于 Matlab 太聪明了。

我有类似的东西

for k=1:N
    stats = subfun(E,k,stats);
end

哪里stats是一个1xN数组,N=5000比如说,从subfun计算,并将其填充到 statsstats(k)E

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

这需要每次重新分配统计数据。

有没有人知道为什么会发生这种情况?

4

2 回答 2

5

这可能是由于 Matlab 的JIT的一些模糊细节。最近版本的 Matlab 的 JIT 知道不创建新数组,而是在某些有限的情况下进行就地修改。要求之一是函数定义为

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 识别它是就地操作。

如果您确实需要加快算法速度,可以使用您自己的 mex-functions就地修改数组。我已经成功地使用这个技巧在一些中型阵列(订购 100x100x100 IIRC)上获得了 4 倍的加速。但是不建议这样做,如果您不小心,可能会导致 Matlab 出现段错误,并且可能会在以后的版本中停止工作。

于 2013-09-26T18:17:35.773 回答
0

正如其他人所讨论的,问题几乎肯定在于 JIT 及其相对脆弱的就地修改能力。

如前所述,我真的更喜欢第一种形式的函数调用和赋值,尽管已经提出了其他可行的解决方案。在不依赖 JIT 的情况下,唯一有效的方法(据我所知)是某种形式的按引用传递。

因此,我创建了一个Stats继承自句柄的类,其中包含k=1:N. 然后通过引用传递。

为了将来参考,这似乎工作得很好,性能很好,我目前正在使用它作为我的工作解决方案。

于 2013-09-27T07:09:58.230 回答