Лучшая практика для индекса 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
, по сравнению с созданием значений индекса "на лету".