2016-03-17 2 views
12

У меня есть большая матрица 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)

ответ

21

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

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' - только для Векторы действительных чисел, without the attribute complex. Вместо этого используйте .'.
  • B=permute(A,p) - только для случаев, когда all(A(:)==B(:)).
  • B=ipermute(A,p) - только для случаев, когда all(A(:)==B(:)).
  • B=squeeze(A)
  • shiftdim - только для тех случаев, когда all(A(:)==B(:)), которые являются:
    • используется для удаления ведущих одноэлементные размеров.
    • используется с отрицательным вторым входом
    • используется без ввода второго аргумента.

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

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

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

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

Смежные вопросы