Лучшая практика для индекса MATLAB для цикла

Я с удивлением обнаружил следующую разницу между запуском циклов MATLAB для:

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

Единственное отличие заключается в том, как создается индексный список. Я бы заподозрил, что вторая версия будет быстрее, но lo!

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

Мой вопрос двоякий: что отвечает за вышеприведенный результат, а где еще этот нюанс (или аналогичный) происходит в программировании MATLAB? Я надеюсь, что смогу лучше определить эти неэффективности в будущем. Спасибо всем.

Ответ 1

В документации в for() указано:

for index = values
   ...
end

где values имеет одну из следующих форм:

  • ...

  • valArray: создает индекс столбца из последующих столбцов массива valArray на каждой итерации. Например, на первой итерации index = valArray(:,1). Цикл выполняется максимум n раз, где n - количество столбцов valArray, заданное numel(valArray, 1, :). Вход valArray может быть любого типа данных MATLAB, включая строку, массив ячеек или структуру.

Поэтому я предполагаю, что существует значительная служебная информация, и компилятор не проверяет, использует ли 1:ksize == klist более быструю реализацию. Другими словами, на комментарий Eitan JIT применяется к первым двум типам принятых значений.

Вся проблема связана со следующей задачей индексирования (column vs element):

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 связана с индексированием столбцов, используемой в этом случае.

Дополнительные сведения см. в этом продолжительном обсуждении (неэффективной) индексации.

Ответ 2

Мой ответ - это предположение (потому что только ребята Mathworks знают реализацию своего продукта), но я думаю, что первый цикл k оптимизирован, чтобы не создавать фактический массив индексов, а просто сканировать их один за другим, потому что он явно показывает, как значения "построены". Второй цикл k не может быть оптимизирован, потому что интерпретатор заранее не знает, будет ли содержание индекса массива расти равномерно. Итак, каждый раз, когда цикл начинается, он будет копировать доступ к исходному klist и поэтому у вас есть ограничение производительности.

Более позднее редактирование: Еще одно ограничение производительности может быть связано с индексированным доступом в массиве klist, по сравнению с созданием значений индекса "на лету".