三大技巧實現(xiàn)Perl性能優(yōu)化
本文和大家重點討論一下Perl性能優(yōu)化,Perl是強大的語言,是強大的工具,也是一道非常有味道的菜:-)利用很多perl的特性,可以實現(xiàn)一些非常有趣而實用的功能。
Perl性能優(yōu)化
Perl是強大的語言,是強大的工具,也是一道非常有味道的菜:-)利用很多perl的特性,可以實現(xiàn)一些非常有趣而實用的功能。
利用Perl開發(fā)一些服務(wù)應(yīng)用時,有時會遇到Perl性能或資源占用的問題,如何解決呢?以下是自己過去開發(fā)實踐的一些經(jīng)驗,幾個主要的技巧分別是:
◆巧用require裝載模塊
◆使用系統(tǒng)函數(shù)及XS化模塊
◆自寫低開銷模塊
◆優(yōu)化正則表達式
◆善用BSDsocket
巧用require裝載模塊
為避免程序一啟動就加載大量模塊,降低啟動速度,可以在必要的時候再裝載模塊,這時候就是require大派用場的時候了。
如:
- #!/usr/bin/perl-w
- usepre_load_module;
- #Initializesomething
- init_args();
- #if$use_this_moduleistrue,loadtheModule
- if($use_this_module){
- requireModule;
- }
上述代碼中,如果變量$use_this_module設(shè)置了,那么才加載Module,如果沒設(shè)置則不需要加載,實現(xiàn)了:useondemand的功能。在CGI應(yīng)用程序中,這相當(dāng)有用,如果每次請求(fork)都加載大量無用模塊的話,響應(yīng)速度會有所降低,而在特定場合才加載一些模塊將加塊啟動、解析的速度。
再看一個例子:
- #!/usr/bin/perl
- my$pid=forkordie"can'tfork:$!\n";
- if($pid){
- print"i'mfather\n";
- sleep;
- }else{
- print"i'mchild\n":
- requireIO::Socket;
- sleep;
- }
上述代碼中,如果在程序一開始就用use來載入IO::Socket模塊,那么子/父進程都加載了該模塊,通過top命令發(fā)現(xiàn)子父進程大小都是3.07MB;如果只在子進程里加載,則只在子進程里有效,內(nèi)存的消耗將降低,top命令發(fā)現(xiàn)子進程3.04MB,父進程變?yōu)?.4MB。
使用系統(tǒng)函數(shù)及XS化模塊
Perl內(nèi)建的系統(tǒng)函數(shù)及用c編寫的perlXS擴展模塊的速度和效率都比純perl的實現(xiàn)要好得多。在Perl性能要求較高的場合(如開發(fā)ApplicationServer,NetworkServer等),可以考慮使用這些內(nèi)建函數(shù)或XS化模塊。
如Socket就比IO::Socket的內(nèi)存消耗要低,XS編寫的Data::Dumper就比純Perl的Data::Dumper要快4-5倍。
此外,一些簡單的任務(wù)并沒必要使用Perl模塊,如獲得主機IP地址就大可不必載入龐大的Net::DNS而只是使用gethostbyname()系統(tǒng)函數(shù)即可。
以下是一些常用的替代方案以獲得更快的速度,更好的效率:
用sys*系列函數(shù)等替代open/seek/tell/<>等標準IO操作
用Socket代替IO::Socket以獲得更低開銷和內(nèi)存占用
用get*by*系列函數(shù)代替Net::DNS
用index/substr等代替部分低效正則表達式
用select(3參數(shù)版本)代替IO::Handle部分功能.......
自寫低開銷模塊
通常我們使用一些Perl模塊時,只使用了其中很小一部分的功能,可是卻不得不載入整個模塊,甚至要載入其他不相關(guān)的模塊。因此往往使整個程序非常臃腫龐大。
著名的web管理軟件webmin的miniserv(一個簡化的http服務(wù)端)功能強大,還支持SSL,但資源占用卻出奇的少,只有大約5.6MB的大?。∵@是為什么呢?因為miniserver只使用了2個Perl系統(tǒng)模塊(Socket及POSIX),沒有載入其他的模塊。Perl性能優(yōu)化時一些本需要其他perl模塊的功能,均由web-lib.pl等用系統(tǒng)函數(shù)編寫代替。
例如以下是一個獲得A記錄的高速函數(shù)get_mx(),它不依賴任何模塊,速度非???。
- subget_mx{
- my@info=gethostbynameshift;
- my@addr=splice(@info,4);
- my@rt;
- foreach(@addr){
- push@rt,join('.',unpack('C4',$_));
- }
- \@rt;
- }
另一個例子,對于標準的IO::Handle對象,可以使用$obj->autoflush(1);來設(shè)置緩沖的特性,我們通過使用系統(tǒng)函數(shù)select()來獲得同樣的能力,而無需要載入IO::Handle,代碼如下:
- subautoflush{
- my$io=$_[0];
- select((select($io),$|=1)[0]);
- }
使用方法很簡單,例如要對IO::Socket::INET類型的$sock設(shè)置為立即沖刷,則autoflush($sock)即可。
【編輯推薦】
- 從細節(jié)處提升Perl性能
- Perl模式匹配參數(shù)使用詳解
- 實例解析Perl多進程技術(shù)的應(yīng)用
- 學(xué)習(xí)筆記 Perl split函數(shù)用法指導(dǎo)
- Perl多進程及其和多線程的關(guān)系解析