matlab中for循環為什麼會慢?

最近在看一些matlab代碼向量化的東西,做測試的時候發現,當運算的數量級上去的時候,for循環的代碼會比向量化的代碼慢很多,這是為什麼呢?

Example 1:

&>&> D = rand(10000, 1);
H = rand(10000, 1);
tic
for n = 1:10000
V(n) = 1/12*pi*(D(n)^2)*H(n);
end
toc
Elapsed time is 0.017800 seconds.
&>&> tic
V = 1/12*pi*(D.^2).*H;
toc
Elapsed time is 0.010938 seconds.

當數據量在10000左右的時候可以看到兩種計算方式消耗時間都差不多

Example 2:

&>&> D = rand(10000000, 1);
H = rand(10000000, 1);
&>&> tic
for n = 1:10000000
V(n) = 1/12*pi*(D(n)^2)*H(n);
end
toc
Elapsed time is 3.698054 seconds.
&>&> tic
V = 1/12*pi*(D.^2).*H;
toc
Elapsed time is 0.048087 seconds.

當數據量在10000000的時候可以看到使用for循環的方式消耗時間劇增


@黃夢龍

另一個回答已經說了,主要原因就是就是循環中 V 變數沒有預先聲明,導致在循環中數組大小不斷變化,當大小增長當前數組可能需要複製到新的更大的連續內存中,這顯然會導致不必要的開銷。

如果數組長度較短,發生上述複製過程的次數少一些,而且發生時需要複製的內容也短,所以減速不太明顯。如果很長會怎麼樣不難想像

同時也能想到如果預先聲明足夠大的V則可以避免這一過程。

不過即使預先聲明,在運算數組足夠大的時候等價運算的循環通常也不如向量化快,這是由於向量化只需要調用一次函數,而循環需要在每次循環中都調用函數,這會帶來額外的開銷。同時很多向量化的操作或函數內部是多線程的,而循環是單線程的,性能自然不如向量化快。

另外還有一點需要注意,MATLAB 的代碼在不同位置執行的性能會有不同,通常是 命令窗口&<腳本&<函數,所以要測試性能的話最好在函數中測試,至少也是在腳本中執行:

例如這段代碼我在腳本中運行:

clear
a = rand(1,1e6);
tic
b = a.^2;
toc

所在腳本為foo.m:

&>&> foo
時間已過 0.001611 秒。

而如果放在命令窗口中運行:

&>&> clear
a = rand(1,1e6);
tic
b = a.^2;
toc
時間已過 0.012442 秒。

可以看到能相差七八倍


針對你的例子,在調用for循環時,沒有對循環中的變數V定義空間,V的大小不知道,還要滿足你的計算要求,就導致每次循環都要給V開空間,自然很耗費時間,matlab自身也會給出warning: variable or array appears to be changing with each loop iteration。

如果在循環前先聲明,例如:V=zeros(n),那麼運行時間會節約很多,但還是比向量運算慢,而且和C/C++的for循環相比也很慢,因此還有其他原因,具體為什麼我也沒想明白


預先定義變數不僅可以減少空間浪費,還可以減少重新分配的時間。比在。如果運算量特別巨大,而且每個循環之間沒有建議,可以用parfor代替for,採用多線程


推薦閱讀:

奇數階幻方構造方法的原理是什麼?
這是用什麼演算法實現的?
遞歸有什麼意義?
計算機是怎樣進行開方和冪運算的?
求一千萬以內由兩個素數相乘的數,並按從小到大排列,如:6=2*3,10=2*5。有什麼比較好的思路嗎?

TAG:演算法 | MATLAB | 科學計算 | 向量 |