|
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->Improving Performace and Memory Usage;或MATLAB->Programming Fundamentals->Performace->Techniques for Improveing Performace。 多線程 如果你使用的是多核心的計(jì)算機(jī),那么你就可以讓Matlab同時(shí)運(yùn)行多個(gè)線程,Matlab 程序中一些底層的函數(shù)(Low-level function)就有可能采用并行計(jì)算的方法。打開多線程的方法:File->Preferences選擇 General->Multithreading??圻xEnable multihread computation box。如果不限制使用核心的數(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秒的情況才是值得的。 |
|
|