Почему так быстро меняется?

У меня есть большая матрица A, которая составляет 1 ГБ двойных значений, когда я изменяю ее на разные размеры, это невероятно быстро.

A=rand(128,1024,1024);
tic;B=reshape(A,1024,128,1024);toc

Elapsed time is 0.000011 seconds.

Как это может быть так быстро? Другое наблюдение, MATLAB использует меньше памяти, чем нужно, после запуска этого кода и хранения двух матриц по 1 ГБ каждый: Memory used by MATLAB: 1878 MB (1.969e+09 bytes)

Ответы

Ответ 1

Объяснение хорошей производительности

Matlab использует copy-on-write, когда это возможно. Если вы пишете выражения типа B=A, MATLAB не копирует A, вместо этого обе переменные A и B являются ссылками на одну и ту же структуру данных. Только если одна из двух переменных будет изменена, MATLAB создаст копию.

Теперь к частному случаю reshape. Здесь похоже, что A и B не совпадают, но в памяти они есть. Базовый массив, содержащий данные, не подвергается действию reshape, ничего не нужно перемещать: all(A(:)==B(:)). Все, что нужно MATLAB при вызове reshape, это создать новую ссылку и аннотировать ее новыми измерениями матрицы. Преобразование матрицы - это не что иное, как создание новой ссылки на входные данные, которая аннотируется новыми измерениями. Время выполнения изменения составляет менее 1 мкс или примерно так, как требуется два простых назначения типа B=A. Для всех практических применений используется операция с нулевым временем.

>> tic;for i=1:1000;B=reshape(A,1024,128,1024);end;toc
Elapsed time is 0.000724 seconds.
>> tic;for i=1:1000;B=A;end;toc
Elapsed time is 0.000307 seconds.

Неизвестно, насколько велика такая ссылка, но мы можем предположить, что она находится в пределах нескольких байтов.

Другие операции с нулевой стоимостью

Известные функции имеют практически нулевую стоимость (как время выполнения, так и память):

  • B=reshape(A,sz)
  • B=A(:)
  • B=A.' - только для векторов
  • B=A' - только для векторов действительных чисел без атрибута complex. Вместо этого используйте .'.
  • B=permute(A,p) - только для случаев, когда all(A(:)==B(:)). 1
  • B=ipermute(A,p) - только для случаев, когда all(A(:)==B(:)). 1
  • B=squeeze(A) 1
  • shiftdim - только для случаев, когда all(A(:)==B(:)), которые: 1
    • используется для удаления ведущих размеров синглтона.
    • используется с отрицательным вторым входом
    • используется без ввода второго аргумента.

Функции, которые являются "дорогими", независимо от того, что они не касаются представления в памяти (all(A(:)==B(:)) истинно)

  • Левая односторонняя индексация: B(1:numel(A))=A; 2
  • Правостороннее индексирование, отличное от (:), включая B=A(1:end); и B=A(:,:,:); 2

1 Значительно медленнее время выполнения, чем reshape между 1μs и 1ms. Вероятно, из-за каких-то постоянных издержек вычислений. Потребление памяти практически равно нулю, а время выполнения не зависит от размера ввода. Операции без этой аннотации имеют время работы менее 1 мкс и примерно эквивалентны reshape.

2 Нулевая стоимость в OCTAVE