Matlab和Octave中“for”循环的时间比较

4

刚刚我了解到 Matlab 和 Octave 使用列优先顺序,来源于 Wikipedia

Fortran、OpenGL 和 OpenGL ES、MATLAB、GNU Octave、R、Julia、Rasdaman 和 Scilab 都使用列优先顺序。

所以我只是在检查 Matlab 和 Octave 中的“for循环”速度。以下是结果:

Matlab

>> x = rand(10000);
>> tic; for i=1:10000 for j=1:10000 k=x(i,j); end; end; toc; % row-major
Elapsed time is 2.320215 seconds.
>> tic; for i=1:10000 for j=1:10000 k=x(j,i); end; end; toc; % column-major
Elapsed time is 0.433013 seconds.

作为预期,列优先顺序比行优先顺序更快。
Octave
> x=rand(5000);
> tic; for i=1:5000 for j=1:5000 k=x(i,j); end; end; toc; % row-major
Elapsed time is 77 seconds.
> tic; for i=1:5000 for j=1:5000 k=x(j,i); end; end; toc; % column-major
Elapsed time is 78 seconds.

在这两种情况下,结果是相同的。
问题: 为什么Octave中行主循环和列主循环表现相似,尽管它使用列主对齐?

2
这可能会解释一些问题,特别是Octave缺乏JIT的原因:https://dev59.com/2Wcs5IYBdhLWcg3wynDD - David
1
我已经看过那个链接了。它提供了一个洞察为什么Matlab循环比Octave快得多的原因(对于10000x10000,Matlab只需要0.5秒,而Octave则需要78秒,对于5000x5000),但是似乎没有涉及到我的问题。 - Abid Rahman K
2
重新使用 feature accel off 运行测试,我发现行优先和列优先版本之间没有实质性的区别(与您在 Octave 中的结果非常相似)。因此,时间差异在于 JIT 编译,而我猜测非向量化循环不像 JIT 编译器使用的向量化版本那样依赖于矩阵的访问方式。 - David
1
哦,那很酷。但是为什么Matlab和Octave都没有区别呢?我的意思是,无论如何,按列循环应该更快,对吧? - Abid Rahman K
2个回答

3
为了阐述我的评论,我将发布一个答案。虽然我不是专家。
首先,在Matlab中使用“feature accel off”运行测试以禁用JIT编译会返回与Octave大致相同的结果。因此,Matlab和Octave之间的速度增加是由于Matlab的JIT编译,必须对循环进行矢量化。
其次,Matlab的JIT编译版本比行优先更快的原因是Matlab是列优先的,这是有道理的。
然后,对于没有JIT编译的Octave和Matlab,列优先评估只是稍微快一点。由于每个值都是从随机矩阵中单独提取的,我可以理解为什么这会很慢,但不知道为什么行或列优先之间应该有很大差异。
希望这有所帮助,也许其他人可以扩展/改进这个或发表一个真正的答案!

+1 为答案。但我仍然不明白为什么没有 JIT 没有区别。 - Abid Rahman K
我认为这只是因为每次循环迭代,Matlab/Octave都必须去检索矩阵的单个元素,进行计算,然后检索下一个元素。它没有将矩阵的列加载到缓存中并使用每个元素,而是加载缓存中的单个元素,然后将其删除,然后将下一个元素加载到缓存中。 - David

2

如果您尝试对整列或整行进行操作,您将会看到不同之处。请在MATLAB和Octave中尝试以下代码:

%% Columns
a = rand(n);
b = zeros(n,1);
tic
for ii = 1:n
  b = b + a(:,ii);
end
t1 = toc

%% Rows:
a = rand(n);
b = zeros(1,n);
tic
for ii = 1:n
  b = b + a(ii,:);
end
t2 = toc

在我的电脑上,这个操作会得到以下结果:
%% MATLAB:
t1 =  0.0287
t2 =  0.3778

%% Octave*:
t1 =  0.089480
t2 =  0.20313

现在,Octave中的差异并不像在MATLAB中那么大,但在Octave中仍然存在显着差异(快了两倍以上)。

David已经发表了一篇关于JIT编译的答案,所以我在这里跳过了那部分内容。

*我没有Octave可用,所以我不得不在这里进行测试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接