Profile(分析)
在加速你的matlab程序之前,你需要知道你的代碼哪一部分運(yùn)行最慢。matlab提供個(gè)簡(jiǎn)單的機(jī)制,讓你能夠知道你的代碼的某一部分運(yùn)行所占用CPU時(shí)間。通過在代碼段開始添加tic,及在結(jié)束添加toc;matlab就能計(jì)算出這一代碼段的運(yùn)行時(shí)間。
Tic和toc方法存在兩個(gè)問題:
(1)顯示的時(shí)間是運(yùn)行時(shí)間“wall clock”。這個(gè)時(shí)間受你在運(yùn)行你的代碼時(shí),你的計(jì)算機(jī)是否同時(shí)運(yùn)行其它別的程序。
(2)你需要不斷地壓縮計(jì)時(shí)范圍來查找你代碼運(yùn)行最慢的位置。
一個(gè)最好的方法是利用matlab 內(nèi)嵌的代碼分析器。在你的程序前面通過添加命令profile on;及在程序結(jié)束添加profile viewer;并運(yùn)行你的程序。當(dāng)程序正常運(yùn)行結(jié)束時(shí),代碼分析器窗口將彈出,并顯示分析結(jié)果。它包含的信息有:
Function Name :函數(shù)名;
Calls :函數(shù)被調(diào)用次數(shù);
Total Time :執(zhí)行該函數(shù)的CPU總用時(shí),包含任何其它被它調(diào)用的函數(shù)的CPU時(shí)間。
Self Time :執(zhí)行該函數(shù)的CUP總用時(shí),不包含任何其它被它調(diào)用的函數(shù)的CUP時(shí)間。
Total Time Plot :時(shí)間用時(shí)的曲線圖。
以上信息可進(jìn)行各種排序和詳細(xì)查看。
注意:當(dāng)你完成你的代碼分析后,請(qǐng)刪除profile on和profile viewer,因?yàn)榍度氪a分析器會(huì)使用的程序運(yùn)行變慢。
標(biāo)準(zhǔn)提示
☆有問題找?guī)椭臋n。學(xué)會(huì)使用幫助文檔,學(xué)會(huì)針對(duì)待解決的問題檢索文檔資料。
☆性能
查看MATLAB->Programming->ImprovingPerformace and Memory Usage;或MATLAB->ProgrammingFundamentals->Performace->Techniques for Improveing Performace。
多線程
如果你使用的是多核心的計(jì)算機(jī),那么你就可以讓Matlab同時(shí)運(yùn)行多個(gè)線程,Matlab程序中一些底層的函數(shù)(Low-levelfunction)就有可能采用并行計(jì)算的方法。打開多線程的方法:File->Preferences選擇General->Multithreading??圻xEnable multihread computationbox。如果不限制使用核心的數(shù)目,可以保留使用Automatic。
注意:Matlab R2008a之前的版本在AMD處理器上是不支持多線程的。
向量化循環(huán)
Matlab的運(yùn)算是針對(duì)向量(矢量)和矩陣進(jìn)行設(shè)計(jì)的,因此它在向量和矩陣上的運(yùn)算速度比采用循環(huán)的方式更快。
例如:
index=0;
for time=0:0.001:60;
index=index+1;
waveForm(index)=cos(time);
end;
采用以下代碼可加快速度。
Time=0:0.01:60;
waveForm=cos(time);
一些有用的,可用于代替循環(huán)的函數(shù):
any();size();find();cumsum();sum();
向量預(yù)分配
Matlab采用內(nèi)存中一塊連續(xù)的空間來存儲(chǔ)向量和矩陣數(shù)據(jù),而不是用鏈表。這就意味著你每給向量或矩陣增加一元素,Matlab需要尋找一塊足夠大的內(nèi)存區(qū)域來存儲(chǔ)這個(gè)擴(kuò)大后的向量或矩陣,然后復(fù)制現(xiàn)有的數(shù)據(jù)到新的內(nèi)存區(qū)域。在循環(huán)中增加向量或矩陣元素的元數(shù)是允許的,但并不是明智之舉,而應(yīng)該是一次性分配向量或矩陣的大小,或一次性重定義尺寸。
Results=0;
for index=2:1000;
results(index)=results(index-1)+index;
end
上述代碼將比以下代碼速度慢:
results=zeros(1,1000);
for index=2:1000;
results(kindex)=results(kindex-1)+index;
end;
注意:當(dāng)你需要用zeros()來創(chuàng)建一個(gè)指定數(shù)據(jù)類型的向量或矩陣時(shí),你可以使用創(chuàng)建參數(shù)來指定類型,而不是“重鑄”。results=int8(zeros(1,1000));將創(chuàng)建一個(gè)有1000個(gè)元素的double型零向量,然后把它轉(zhuǎn)換成int8類型。如果我們使用results=zeros(1,1000,'int8');Matlab將支持建立1000個(gè)int8類型的向量,在創(chuàng)建可實(shí)現(xiàn)性及速度上將更具有優(yōu)勢(shì)。
不要改變數(shù)據(jù)類型
Matlab為了能夠支持寬松的數(shù)據(jù)類型(例如一個(gè)變量能夠存儲(chǔ)不同類型的數(shù)據(jù),而不是指定它為特定的數(shù)據(jù)類型),則Matlab除了存儲(chǔ)單純的數(shù)據(jù)之外,還需要伴隨數(shù)據(jù)存儲(chǔ)一定數(shù)量的頭信息(header),這就意味著需要內(nèi)存空間支存儲(chǔ)數(shù)據(jù)類型,同時(shí)意味需要在數(shù)據(jù)類型轉(zhuǎn)換上支付額外的計(jì)算機(jī)資源開支。
對(duì)于實(shí)數(shù)據(jù)使用 real...函數(shù)。
Matlab中的一些函數(shù)能夠同時(shí)適用于實(shí)類型數(shù)據(jù)和復(fù)類型數(shù)據(jù)。如果你只使用實(shí)數(shù)據(jù),那么采用特定的版本的,非復(fù)數(shù)據(jù)函數(shù),那么它運(yùn)行的速度將變得更快。這些函數(shù)如:reallog(), realpow(),realsqrt()。
使用“短路”邏輯操作
Matlab的“短路”邏輯操作可以在判斷條件達(dá)到充分條件后就停止計(jì)算處理,而不需要知道判斷所有條件。例如:if(index>=3)&&(data(index)==5);當(dāng)index小于3時(shí),第二個(gè)條件判斷將不被處理,這樣就少了去判斷data(index)==5)的時(shí)間,提高速度。
使用函數(shù)指針
Matlab的一些函數(shù)使用函數(shù)名作用參數(shù),常用一個(gè)變量支保存這個(gè)函數(shù)名字符串()如:func='tan';然后用這個(gè)變量作為函數(shù)的參數(shù):fzero(func,0))。這種方法對(duì)于簡(jiǎn)單的函數(shù)調(diào)用是很好的,但是對(duì)于在循環(huán)中的重復(fù)調(diào)用就存在兩個(gè)問題:
(1)在每一個(gè)循環(huán)中,Matlab需要去搜索這個(gè)函數(shù)的路徑(如tan),這需要花費(fèi)時(shí)間。
(2)在循環(huán)過程中,路徑可能會(huì)改變。這會(huì)保證在這一次循環(huán)中,某個(gè)版本的函數(shù)(如tan)被首先調(diào)用,而下一次循環(huán)中這個(gè)版本的函數(shù)又被首先調(diào)用,最終會(huì)造成結(jié)果不一致。
解決的辦法是使用文件指針(func=@tan;或func=@sin),它能返回函數(shù)唯一的識(shí)別碼。調(diào)用方式同上。
文件I/O
通常高級(jí)輸入輸出操作(load()和save())比一般的低級(jí)操作(fread()和fwrite())快。
☆內(nèi)存使用
關(guān)于內(nèi)存的使用可查看幫助文檔Using Menory Efficently??刹榕cMemory Usage相關(guān)的信息。
一定記注:可以使用whos()來查看數(shù)據(jù)變量占有用的內(nèi)存空間大小。
復(fù)制數(shù)組
當(dāng)你復(fù)制一個(gè)數(shù)組時(shí),Matlab開始只復(fù)制一個(gè)指向數(shù)據(jù)的一個(gè)指針,僅當(dāng)你隨后對(duì)任一版本進(jìn)行修時(shí),數(shù)據(jù)的復(fù)制才真正的執(zhí)行。這種操作包括數(shù)組作為函數(shù)參數(shù)進(jìn)行傳遞的情況-作為值傳遞的參數(shù)傳遞,而不是作為參考的傳遞。因此,你應(yīng)該盡量避開對(duì)大數(shù)組進(jìn)行小改動(dòng)的操作。
數(shù)據(jù)不用時(shí),釋放內(nèi)存
如果一個(gè)變量以后已經(jīng)不再使用,那么你可以刪除它c(diǎn)lear VariableName;則這個(gè)小塊的數(shù)據(jù)將可以重用。
注意:如果各變量在內(nèi)存是連續(xù)的,則Matlab很容易重用這些大塊的內(nèi)存,因此最好是先建立大的變量,后再建立小的變量,并且把它們組合起來。
結(jié)構(gòu)體存儲(chǔ)
上文已經(jīng)提到,在Matlab中的變量包含有描述數(shù)據(jù)類型的頭信息。對(duì)于一個(gè)結(jié)構(gòu)體,則有一個(gè)描述整個(gè)結(jié)構(gòu)的頭信息,及每個(gè)元素也分別有一個(gè)頭信息。為了最小化地使用內(nèi)存,我們應(yīng)該小心地使用混合數(shù)據(jù)類型的數(shù)組和結(jié)構(gòu)。
例如:
pixel.red(1:600,1:400)
pixel.grn(1:600,1:400)
pixel.blu(1:600,1:400)
則我們就需要存儲(chǔ)4個(gè)頭信息。而:
pixel(1:600,1:400).red
pixel(1:600,1:400).grn
pixel(1:600,1:400).blu
我們就有720001個(gè)頭信息。
使用最小的合適的數(shù)據(jù)類型
為了減小內(nèi)存使用量,對(duì)于特定的運(yùn)算經(jīng)常使用最小的數(shù)據(jù)類型。例如:
(1)對(duì)于虛部為零的數(shù)據(jù),最好不要用complex去存儲(chǔ)。
(2)如果精度足夠,可采用single變量,而不用double。
(3)使用uint16來進(jìn)行計(jì)數(shù)操作,它能存儲(chǔ)值為0到65535。但它比默認(rèn)的double型省一半的內(nèi)存。
使用稀疏矩陣
如果矩陣絕大多的數(shù)據(jù)為零值,可以把它轉(zhuǎn)化成稀疏形式(使用sparse()函數(shù))。它將只存儲(chǔ)非零數(shù)據(jù)的數(shù)值和索引。因?yàn)樾枰~外的存儲(chǔ)數(shù)據(jù)的索引,因此只有二維數(shù)據(jù)的零值大約超過75%時(shí),這種方法才是有效的,否則稀疏形式反而需要更多的內(nèi)存空間。
☆并行循環(huán)
如果從一個(gè)for循環(huán)的外部看,for循環(huán)滿足以下標(biāo)準(zhǔn):
(1)循環(huán)的計(jì)數(shù)是整數(shù);
(2)每次循環(huán)都是獨(dú)立的;
(3)計(jì)算循環(huán)先后順序無關(guān)。
那么這個(gè)for循環(huán)就有可能可以替換成parfor循環(huán)(matlab2008a中可用優(yōu)化算打開并行通信池:parfor循環(huán)包含于matlabpool open 和matlabpool close之間)。
注意:打開一個(gè)并行工作池worker pool大約需要10-15秒鐘,關(guān)閉一個(gè)工作池大概需要5秒鐘。計(jì)算這個(gè)時(shí)間在內(nèi),這個(gè)方法對(duì)于循環(huán)時(shí)間超過30秒的情況才是值得的。
聯(lián)系客服