預分配的重要性
MATLAB 中的陣列作為連續塊儲存在記憶體中,由 MATLAB 自動分配和釋放。MATLAB 隱藏了記憶體管理操作,例如在易於使用的語法背後調整陣列大小:
a = 1:4
a =
1 2 3 4
a(5) = 10 % or alternatively a = [a, 10]
a =
1 2 3 4 10
重要的是要理解上面不是一個簡單的操作,a(5) = 10
將導致 MATLAB 分配一個大小為 5 的新記憶體塊,複製前 4 個數字,並將第 5 個數字設定為 10.這是一個 O(numel(a))
操作,而不是 O(1)
。
考慮以下:
clear all
n=12345678;
a=0;
tic
for i = 2:n
a(i) = sqrt(a(i-1)) + i;
end
toc
Elapsed time is 3.004213 seconds.
a
在此迴圈中重新分配了 5 次(不包括 MATLAB 進行的一些優化)! 請注意,MATLAB 給出了一個警告:
“變數’a’似乎在每次迴圈迭代時改變大小。考慮預先分配速度。”
我們預先分配時會發生什麼?
a=zeros(1,n);
tic
for i = 2:n
a(i) = sqrt(a(i-1)) + i;
end
toc
Elapsed time is 0.410531 seconds.
我們可以看到執行時間減少了一個數量級。
預分配方法:
MATLAB 根據使用者的具體要求提供各種向量和矩陣分配功能。這些包括: zeros
, ones
, nan
, eye
, true
等。
a = zeros(3) % Allocates a 3-by-3 matrix initialized to 0
a =
0 0 0
0 0 0
0 0 0
a = zeros(3, 2) % Allocates a 3-by-2 matrix initialized to 0
a =
0 0
0 0
0 0
a = ones(2, 3, 2) % Allocates a 3 dimensional array (2-by-3-by-2) initialized to 1
a(:,:,1) =
1 1 1
1 1 1
a(:,:,2) =
1 1 1
1 1 1
a = ones(1, 3) * 7 % Allocates a row vector of length 3 initialized to 7
a =
7 7 7
還可以指定資料型別:
a = zeros(2, 1, 'uint8'); % allocates an array of type uint8
克隆現有陣列的大小也很容易:
a = ones(3, 4); % a is a 3-by-4 matrix of 1's
b = zeros(size(a)); % b is a 3-by-4 matrix of 0's
並克隆型別:
a = ones(3, 4, 'single'); % a is a 3-by-4 matrix of type single
b = zeros(2, 'like', a); % b is a 2-by-2 matrix of type single
注意’喜歡’也克隆了複雜性和稀疏性。
使用任何返回最終所需大小陣列的函式隱式實現預分配,例如 rand
, gallery
, kron
, bsxfun
, colon
等等。例如,分配具有線性變化元素的向量的常用方法是使用冒號運算子(使用 2 或 3 運算元變數 1 ):
a = 1:3
a =
1 2 3
a = 2:-3:-4
a =
2 -1 -4
可以使用 cell()
函式分配單元陣列,其方式與 zeros()
非常相似。
a = cell(2,3)
a =
[] [] []
[] [] []
請注意,單元格陣列的工作方式是將指標指向單元格內容的記憶體中的位置。因此,所有預分配技巧也適用於單個單元陣列元素。
進一步閱讀:
- 關於預分配記憶體的官方 MATLAB 文件 。
- 關於MATLAB 如何分配記憶體的官方 MATLAB 文件 。
- 未記錄的 matlab 上的預分配效能 。
- 瞭解陣列預分配上 基於 MATLAB 的藝術洛倫