在Matlab中编写“ for”循环的最有效方法是什么?


12

我已经读过,例如,如果我有一个for在矩阵索引上运行的双循环,那么将列运行索引放在外部循环中会更有效。例如:

a=zeros(1000);
for j=1:1000
 for i=1:1000
  a(i,j)=1;
 end
end

如果我有三个或更多for循环,最有效的编码方式是什么?

例如:

a=zeros(100,100,100);
for j=1:100
 for i=1:100
  for k=1:100
   a(i,j,k)=1;
  end
 end
end

4
For在MATLAB中循环很慢。您应尽可能避免在MATLAB中进行显式循环。相反,通常可以用矩阵/矢量运算来表达问题。那就是MATLAB的方式。还有很多内置的函数可以初始化矩阵,等等。例如,有一个函数ones(),它将把矩阵的所有元素设置为1(扩展名,乘以任意值(标量)乘以全一矩阵))。它也适用于3-D数组(我认为这里涵盖了示例)。
彼得·莫滕森

3
@PeterMortensen与C和Python相比,Matlab中的循环效率大约要降低哪个因素?为什么是这样?而且,最近几年Matlab中的循环效率没有提高吗?
TensoR

3
@PeterMortensen“通常可以用矩阵/向量运算来表达问题” –对于“通常”的某些值,是的。IMO更准确地说,在Matlab等公司工作的人有着数十年的文化,他们忽略了矩阵/矢量运算无法完成的所有工作,以至于所有东西都像锤子一样钉在他们身上。而且我们不应该只是说“ Matlab中的for循环很慢”,而是“ Matlab速度很慢”(它恰好链接到用C和Fortran编写的LA原语的快速库)。
大约


@leftaroundabout正确。担心使用一种解释(或半解释)语言的速度非常明显地表明您有一个XY问题,其中实际的解决方案是“不要使用该语言”。当然例外是,如果您在Simulink中使用代码生成,但是问题是代码生成器生成什么C,以及它的效率如何。
格雷厄姆

Answers:


18

简短的答案是,您想在最里面的循环上找到最左边的索引。在您的示例中,循环索引将为k,j,i,数组索引将为i,j,k。这与MATLAB如何在内存中存储不同维度有关。有关更多信息,请参阅此reddit帖子的#13 。


2
或使用内置函数ones()
彼得·莫滕森

5
@Peter OP的示例几乎可以肯定只是一个for循环的玩具示例,它可以执行某些操作,而不是实际用例。
马特

@马特你是正确的。
TensoR

11

更长的答案可以解释为什么最左边的索引变化最快的效率更高。您需要了解两个关键事项。

首先,MATLAB(以及Fortran,但不是C和大多数其他编程语言)将数组以“列主要顺序”存储在内存中。例如,如果A是2 x 3 x 10矩阵,则条目将按以下顺序存储在内存中

A(1,1,1)

A(2,1,1)

A(1,2,1)

A(2,2,1)

A(1,3,1)

A(2,3,1)

A(1,1,2)

A(2,1,2)

...

A(2,3,10)

列主要顺序的这种选择是任意的-我们可以轻松地采用“行主要顺序”的约定,实际上,这就是用C和其他一些编程语言完成的工作。

您需要了解的第二件事是,现代处理器不会一次访问一个位置的内存,而是加载和存储64甚至128个连续字节(8或16个双精度浮点数)的“缓存行”一次从内存中取出。这些数据块被临时存储在快速内存缓存中,并根据需要写回。(实际上,高速缓存体系结构现在已经非常复杂,最多有3或4个级别的高速缓存,但是基本思想可以用我较年轻时使用的那种单级高速缓存来解释。)

A

如果循环是嵌套的,以便最内层的循环更新行下标,则将按A(1,1),A(2,1),A(3,1),...的顺序访问数组项。在访问第一个条目A(1,1)时,系统会将包含A(1,1),A(2,1),...,A(8,1)的高速缓存行从主内存中带入高速缓存。最内层循环的接下来的8次迭代将对此数据进行处理,而无需进行任何其他主存储器传输。

如果在另一种情况下,我们对循环进行结构化,以使列索引在最内部的循环中变化,那么将按以下顺序访问A的条目:A(1,1),A(1,2),A(1,3) ),...在这种情况下,第一次访问会将A(1,1),A(2,1),...,A(8,1)从主内存中移入高速缓存,但是这些条目将不会被使用。然后,在第二次迭代中访问A(1,2)将会从主存储器中再引入8个条目,依此类推。等到代码开始在矩阵的第2行上工作时,A(2,1)条目很可能会从缓存中清除出来,以便为其他所需数据腾出空间。结果,该代码产生的流量是所需数量的8倍。

一些优化的编译器能够自动重构循环,以避免出现此问题。

可以对许多用于矩阵乘法和分解的数值线性代数算法进行优化,以根据编程语言有效地使用行优先或列优先排序方案。错误地执行此操作可能会对性能产生重大负面影响。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.