2013-05-30 40 views
4

我寫了一段時間的MATLAB腳本,但仍然不明白它是如何工作的「引擎蓋下」。考慮下面的腳本,它使用(大)向量以三種不同的方式進行一些計算:MATLAB快速(分量)矢量操作...真的很快

  1. MATLAB矢量操作;
  2. 簡單的循環,組件明智地做相同的計算;
  3. 一個優化週期,應該比2.快,因爲避免了一些分配和一些分配。

下面是代碼:

N = 10000000; 

A = linspace(0,100,N); 
B = linspace(-100,100,N); 
C = linspace(0,200,N); 
D = linspace(100,200,N); 

% 1. MATLAB Operations 
tic 
C_ = C./A; 
D_ = D./B; 

G_ = (A+B)/2; 
H_ = (C_+D_)/2; 
I_ = (C_.^2+D_.^2)/2; 

X = G_ .* H_; 
Y = G_ .* H_.^2 + I_; 
toc 
tic 
X; 
Y; 
toc 

% 2. Simple cycle 
tic 
C_ = zeros(1,N); 
D_ = zeros(1,N); 
G_ = zeros(1,N); 
H_ = zeros(1,N); 
I_ = zeros(1,N); 
X = zeros(1,N); 
Y = zeros(1,N); 
for i = 1:N, 
    C_(i) = C(i)/A(i); 
    D_(i) = D(i)/B(i); 

    G_(i) = (A(i)+B(i))/2; 
    H_(i) = (C_(i)+D_(i))/2; 
    I_(i) = (C_(i)^2+D_(i)^2)/2; 

X(i) = G_(i) * H_(i); 
Y(i) = G_(i) * H_(i)^2 + I_(i); 
end 
toc 
tic 
X; 
Y; 
toc 

% 3. Opzimized cycle 
tic 
X = zeros(1,N); 
Y = zeros(1,N); 
for i = 1:N, 
    X(i) = (A(i)+B(i))/2 * ((C(i)/A(i) + D(i)/B(i)) /2); 
    Y(i) = (A(i)+B(i))/2 * ((C(i)/A(i) + D(i)/B(i)) /2)^2 + ((C(i)/A(i))^2 + (D(i)/B(i))^2)/2; 
end 
toc 
tic 
X; 
Y; 
toc 

我知道一個應該總是試圖向量化計算,是MATLAB建立了矩陣/矢量(因此,如今,它並不總是最好的選擇),所以我期待的東西,如:

C = A .* B; 

快於:

for i in 1:N, 
    C(i) = A(i) * B(i); 
end 

我是而不是即使在上面的腳本中,儘管我使用的第二個和第三個方法只經歷了一個循環,但第一個方法執行了許多向量操作(理論上,每次都是「for」循環)。這種力量我得出結論MATLAB有一些神奇的允許(例如)到:

C = A .* B; 
D = C .* C; 

要運行多單「表示」裏面的一些操作週期更快

所以:

  1. 什麼魔術這避免了第1部分中執行得這麼快?
  2. 當你寫「D = A * B」時,MATLAB實際上是用一個「for」循環做一個組件明智的計算,還是簡單地跟蹤D包含「bla」和「bla」的一些乘法?

編輯

  1. 假設我要實現相同的計算使用C++(使用也許有些庫)。將會是第一種MATLAB的方法比在C++中實現的第三種方法更快嗎? (我會回答這個問題我自己,給我一些時間。)

EDIT 2

按照要求,這裏有實驗運行時間:

1部分:0.237143

第2部分:4.440132 其中0。195154用於分配

3部分:

1部分:其中0.057500用於分配

和沒有JIT 2.280640 的0.337259

第2部分:其中0.033886用於分配

149.602017 的

第3部分:82.167713 其中0.010852分配

+1

請您用實測的計算時間來補充您的實驗。 – zellus

+1

+1,我期待着答案! =) –

+0

魔術是JIT加速器([just just time compilation](http://en.wikipedia.org/wiki/Just-in-time_compilation))。在運行'feature('accel','off')後嘗試你的代碼' - 我警告你,這將需要一段時間。不要忘記用'feature'('accel','on')'把它重新打開。 – horchler

回答

3

第一個是最快的,因爲向量化代碼可以輕鬆解釋爲少量優化的C++庫調用。 Matlab也可以對其進行更高級別的優化,例如,在其核心中將G*H+I替換爲優化的mul_add(G,H,I)而不是add(mul(G,H),I)

第二個不能輕鬆轉換爲C++調用。它必須被解釋或編譯。用於腳本語言的最現代的方法是JIT編譯。 Matlab JIT編譯器不是很好,但並不意味着它必須如此。我不知道MathWorks爲什麼不改進它。因此,#2執行得如此之慢以至於即使它進行了更多「數學」操作,#1也更快。

Julia語言被髮明是Matlab表達式和C++速度之間的折衷。相同的非矢量化代碼(julia vs matlab)工作速度非常快,因爲JIT編譯非常好。

+0

這很有道理。這意味着實際上不是*真的很快*的向量化代碼,而是執行非常慢*的for循環。 I.e .:這是否意味着移植到沒有這個問題的語言(編譯語言,例如C++),以及如何將代碼編寫爲第二部分,會導致在Matlab中執行的第一部分的執行w.r.t更快? – FilippoL

+1

C++實際上是冠軍。它運行速度非常快,不僅因爲它被編譯爲本機代碼。它是靜態類型的,非託管的(更少的引用,更多的值是CPU緩存友好的),模板複製粘貼也生成快速代碼並允許優化。 Fortran有更好的編譯器,但是你不能在Fortran中使用像Armadillo這樣的好看的庫。 –

+0

這是關於C++的。不幸的是,未經矢量化的Matlab代碼甚至比Javascript V8更慢,特別是當您進行大量循環,函數調用和閉包時。但是矢量化可以比C++循環更快,因爲理論上可以執行高級優化。但它看起來像我的營銷。 –

0

關於性能優化,我使用'for' loop vs vectorization in MATLAB中提到的兩種方法使用profiler來跟蹤@memyself建議。

出於教育目的,它是有道理的實驗數值算法,對於任何我會去與經過充分驗證的libraries

+0

事實上,當我試圖將Matlab代碼移植到Blitz ++時,我的問題就出現了。我問自己:「如果當我完成我的C++端口時,我發現Matlab仍然比端口更快?」。所以我解除了我的代碼發現做一些運行時測試。現在我會嘗試將腳本移植到更快的語言。 – FilippoL