MATLAB for 循环索引的最佳实践

Posted

技术标签:

【中文标题】MATLAB for 循环索引的最佳实践【英文标题】:Best practice for MATLAB for loop index 【发布时间】:2013-04-10 04:36:37 【问题描述】:

我惊讶地发现运行 MATLAB for 循环之间的成本差异如下:

ksize = 100;
klist = 1:ksize;

tic
for m = 1:100000        
    for k = 1:ksize

    end        
end
toc

tic
for m = 1:100000        
    for k = klist

    end        
end
toc

唯一的区别是创建索引列表的方式。我会怀疑第二个版本会更快,但是瞧!

Elapsed time is 0.055400 seconds.
Elapsed time is 1.695904 seconds.

我的问题是双重的:是什么导致了上述结果,以及这种细微差别(或类似的细微差别)在 MATLAB 编程中还出现在哪里?我希望将来能够更好地发现这些低效率。谢谢大家。

【问题讨论】:

这可能是由于 JIT 加速造成的,因为如果您使用 feature accel off 将其关闭,则两次运行都会得到相似的结果。 【参考方案1】:

我的回答是推测(因为只有 Mathworks 的人知道他们产品的实现),但我认为第一个 k 循环经过优化,不会创建实际的索引数组,而是一个一个地扫描它们,因为它明确地显示了这些值是如何“构建”的。第二个k 循环无法优化,因为解释器事先不知道索引数组的内容是否会均匀增长。因此,每次循环开始时,它都会复制访问原始的klist,这就是为什么会有性能损失。

稍后编辑:与“动态”创建索引值相比,另一个性能损失可能来自对 klist 数组的索引访问。

【讨论】:

我想知道您是否可以通过创建一个派生自double 并覆盖copy 的类来测试这个... @wakjah 检查过,这与复制无关(实际上并没有发生复制——我认为写时复制仍然有效)。这是关于klist 中的下标引用。我更正了 mt 帖子。谢谢你的想法。 @wakjah 另一方面,copy 适用于句柄子类,并且不能同时继承值 句柄类(至少在我拥有的 R2010a 中没有) .我想知道我是否真的覆盖了任何东西......:D 这是真的......那么可能在值类的构造函数/subsasgn 中?【参考方案2】:

for() 中的文档指出:

for index = values
   ...
end

其中values 具有以下形式之一:

...

valArray:在每次迭代时从数组valArray 的后续列创建列向量索引。例如,在第一次迭代中,index = valArray(:,1)。循环最多执行n 次,其中n 是valArray 的列数,由numel(valArray, 1, :) 给出。输入 valArray 可以是任何 MATLAB 数据类型,包括字符串、元胞数组或结构。

因此,我假设存在很大的开销,并且编译器不会检查1:ksize == klist 是否可以利用更快的实现。换句话说,根据 Eitan 的评论,JIT 适用于前两种类型的接受的

整个问题与以下索引任务(列与元素)有关:

tic
for m = 1:100000        
    for k = 1:ksize
        klist(:,k);
    end        
end
toc

tic
for m = 1:100000        
    for k = 1:ksize
        klist(k);
    end        
end
toc

Index column:  ~2.9 sec
Index element: ~0.28 sec

您可以看到klist(:,k) 如何有效地减慢更快的循环,这表明for k = klist 中的问题与本例中使用的列索引有关。

有关更多详细信息,请参阅此lengthy discussion on (inefficient) indexing。

【讨论】:

以上是关于MATLAB for 循环索引的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

Partials vs for 循环——最佳实践

OpenMP/C++:并行 for 循环,之后减少 - 最佳实践?

声明for循环变量最佳实践

Object/Map 何为最佳实践

MySQL 索引 - 最佳实践是啥?

Opensearch - 索引的最佳实践