2014-04-21 29 views
4

我想學習一點朱莉婭,閱讀手冊了幾個小時後,我寫了下面的代碼:如何提高這段代碼的性能?

ie = 200; 
ez = zeros(ie + 1); 
hy = zeros(ie); 

fdtd1d (steps)= 
    for n in 1:steps 
     for i in 2:ie 
      ez[i]+= (hy[i] - hy[i-1]) 
     end 
     ez[1]= sin(n/10) 
     for i in 1:ie 
      hy[i]+= (ez[i+1]- ez[i]) 
     end 
    end 

@time fdtd1d(10000); 
elapsed time: 2.283153795 seconds (239659044 bytes allocated) 

我相信這是在優化,因爲它比相應的數學慢得多:

ie = 200; 
ez = ConstantArray[0., {ie + 1}]; 
hy = ConstantArray[0., {ie}]; 

fdtd1d = Compile[{{steps}}, 
    Module[{ie = ie, ez = ez, hy = hy}, 
    Do[ez[[2 ;; ie]] += (hy[[2 ;; ie]] - hy[[1 ;; ie - 1]]); 
    ez[[1]] = Sin[n/10]; 
    hy[[1 ;; ie]] += (ez[[2 ;; ie + 1]] - ez[[1 ;; ie]]), {n, 
     steps}]; [email protected]; [email protected]]]; 

result = fdtd1d[10000]; // AbsoluteTiming 
{0.1280000, Null} 

那麼,如何讓fdtd1d的Julia版本更快?

回答

5

兩件事:

第一次運行函數時,時間將包括代碼的編譯時間。如果您想讓蘋果在Mathematica中與編譯函數進行比較,您應該運行該函數兩次,然後執行第二次運行。你的代碼我得到:

elapsed time: 1.156531976 seconds (447764964 bytes allocated) 

第一次運行,其中包括當你不需要編譯第二次運行編譯時和

elapsed time: 1.135681299 seconds (447520048 bytes allocated) 

第二件事,可以說是更大的事情,是你應該在性能關鍵代碼中避免全局變量。這是the performance tips section of the manual中的第一條提示。

下面是使用局部變量相同的代碼:

function fdtd1d_local(steps, ie = 200) 
    ez = zeros(ie + 1); 
    hy = zeros(ie); 
    for n in 1:steps 
     for i in 2:ie 
      ez[i]+= (hy[i] - hy[i-1]) 
     end 
     ez[1]= sin(n/10) 
     for i in 1:ie 
      hy[i]+= (ez[i+1]- ez[i]) 
     end 
    end 
    return (ez, hy) 
end 

fdtd1d_local(10000) 
@time fdtd1d_local(10000); 

我的機器上比較你的Mathematica代碼給出

{0.094005, Null} 

而從@timefdtd1d_local結果是:

elapsed time: 0.015188926 seconds (4176 bytes allocated) 

或約6倍更快。全局變量有很大的不同。

+1

在我的電腦中,它需要0.018759438秒。您的答案使手冊的這一部分更加清晰! – xzczd

+1

雖然我討厭承認它,但當「steps」更大時,Julia擊敗_Mathematica_ ... for steps = 10^7 _Mathematica_大約需要103秒,而Julia只需要大約19秒。 – xzczd

0

我相信只使用有限數量的循環並且只在需要時才使用循環。表達式可以用來代替循環。避免所有的循環是不可能的,但是如果我們減少一些代碼,代碼會被優化。 在上面的程序中,我使用表達式進行了一些優化。時間幾乎減少了一半。

原代碼:

ie = 200; 
ez = zeros(ie + 1); 
hy = zeros(ie); 

fdtd1d (steps)= 
    for n in 1:steps 
     for i in 2:ie 
      ez[i]+= (hy[i] - hy[i-1]) 
     end 
     ez[1]= sin(n/10) 
     for i in 1:ie 
      hy[i]+= (ez[i+1]- ez[i]) 
     end 
    end 

@time fdtd1d(10000); 

輸出是

julia> 
elapsed time: 1.845615295 seconds (239687888 bytes allocated) 

優化代碼:

ie = 200; 
ez = zeros(ie + 1); 
hy = zeros(ie); 

fdtd1d (steps)= 
    for n in 1:steps 


     ez[2:ie] = ez[2:ie]+hy[2:ie]-hy[1:ie-1]; 
     ez[1]= sin(n/10); 
     hy[1:ie] = hy[1:ie]+ez[2:end]- ez[1:end-1] 

    end 

@time fdtd1d(10000); 

OUTPUT

julia> 
elapsed time: 0.93926323 seconds (206977748 bytes allocated) 
+0

在我的電腦中,您的優化代碼只需要0.366747729秒。好吧,奇怪的是,我認爲手冊建議我們去除表達式的devector ... – xzczd

+4

雖然這種方法是如何在大多數高級數字語言中優化代碼的,但這與Julia應該做的事情完全相反。 John Myles White在R和Julia中比較了向量化和devectorization方面的優秀職位:http://www.johnmyleswhite.com/notebook/2013/12/22/the-relationship-between-vectorized-and-devectorized-code/。這裏真正的表現罪魁禍首是數據處於非恆定的全局變量中。向量化有點幫助,因爲它減少了變量作爲全局變量的影響,但正確的解決方法是將其包含在一個let或函數中。 – StefanKarpinski