物件 (Objects) perlref, perlmod, perlobj, perltie 資料結構 (Data Structures) perlref, perllol, perldsc 模組 (Modules) perlmod, perlmodlib, perlsub 正規表示法 (Regexps) perlre, perlfunc, perlop 升級至 Perl5 (Moving to perl5) perltrap, perl 與 C連結 (Linking w/C) perlxstut, perlxs, perlcall, perlguts, perlembed 雜項 (Various) http://www.perl.com/CPAN/doc/FMTEYEWTK/index.html (不是說明文件,但還是很有用)
perltoc裡有一份粗略的 perl 說明文件組的目錄。
perldebug(1)
說明文件裡提到的 Perl
除蟲器,在一個「空的」(譯者:即不存在的)程式上執行,像這樣:
perl -de 42
接下來所打入的任意合法 Perl程式碼皆會立刻被評估。同時,你可以檢查符號表 (symbol table)、取得堆疊的記錄 (stack backtraces)、檢視變數值、設定阻斷點 (set breakpoints) 以及其他符號式除蟲器 (symbolic debuggers) 所能作的動作。
-w
嗎?
你試過 use strict
嗎?
你是否檢查過每個系統呼叫 (system call)所傳回的值?
讀了 perltrap說明文件嗎?
你試過 perldebug裡所提到的 Perl除蟲器嗎?
perl -MO=Xref[,OPTIONS] foo.pl
indent(1)
可以將原始碼格式美化,但 Perl並沒有能做得像它那麼好的東西。掃瞄器 (scanner)
和分析器 (parser)
間複雜的反饋 (feedback)(把 vgrind
和 emacs等程式搞混的就是這反饋)使得撰寫一個獨立的 Perl
分析器成了一項艱巨的挑戰。
當然,若你直接照 perlstyle裡面的指示寫程式,就根本沒有必要重新安排格式。
你所用的編輯器可以並也應能幫你把原始碼的格式弄漂亮些。像 emacs的 perl-mode就能幫你把大部分 (但非全部)的程式碼排列得漂亮些,而其它普通的編輯器也能提供一定程度的協助。
如果你試著使用 vgrind程式從雷射印表機印出漂亮的原始碼,可以參考: http://www.perl.com/CPAN/doc/misc/tips/working.vgrind.entry ,但是碰到複雜的程式碼可能就不能全然令人滿意了。
在 perl原始碼的目錄下,你會找到一個叫作 ``emacs'' 的目錄,裡面包括一個 cperl-mode 可以把程式中的關鍵字上色、提供內文相關的協助以及其它方便的功能。
注意:``main'foo''(其中的單引號)會讓 emacs的 perl-mode生病,並且會弄亂內 縮 (indentation) 與精華 (hilighting)。不過你本來就該用 ``main::foo''的 (譯者按: main'foo 是表示模組或 package的舊式寫法;新式的 [perl5的]寫法是 main::foo)。
其它方法包括自動載入較少使用的 Perl 程式碼。請參看標準 perl 套件中的 AutoSplit及 AutoLoader模組的用法。或當你能斷定程式執行效率的瓶頸在何處時,用 C來寫那個部份,就像用組合語言來撰寫 C程式的瓶頸部份一樣。與此法相近的是使用以 C撰寫瓶 頸部份的模組 (例如 CPAN中的 PDL 模組)。
在某些情況下,使用後端的編譯器把程式編譯成位元碼 (byte code)(可節省編譯時間) 或是將 perl程式轉編譯為 C程式的作法值得一試;這些作法絕對會節省編譯的時間並且有時能省一些[但不多]執行時間 。請參考“編譯你的 Perl程式”這個問題的答案。
如果你目前是將你的 perl直譯器動態連結到 libc.so的話,重新作一份靜態連結到 libc.a的 perl直譯器可以提高 10-25%的執行效能。雖然這會使你的 perl直譯器變得更胖,但你的 Perl程式 (及程式設計者) 或許會因此而感謝你。詳情請參考 perl標準套件原始碼版本中的 INSTALL 檔案。
一些未經證實的報告中宣稱有些使用 sfio的 Perl直譯器表現得比沒有用 sfio的還好 (針對於 IO頻繁的應用程式)。想試試看?參考 perl套件原始程式版中的 INSTALL 檔案,尤其是 ``Selecting File IO mechanisms''這一段。
使用 undump程式把編譯後的檔案格式存到硬碟裡以加快執行的速度已經是老掉牙的手法了。它已不再是個可行的方法,因為這方法只有幾種平台能用,況且它終究不是個治本之 道。
在某些情況下,使用 substr()
或 vec()
來模擬陣列有很大的好處。例如,一個有上千
個布林代數值的陣列將佔用至少 20,000位元組的空間,但是它可以被轉變為一個 125位元組的位元向量 (bit vector)以節省相當可觀的記憶體。標準套件中的 Tie::SubstrHash模組也能夠幫助特定形態的資料結構節省些記憶體。若你正在和一些特殊的資料結構奮戰 (例如,矩陣),用
C寫的模組所耗掉的記憶體可能低於同功能並用 Perl寫的模組。
另一件值得一試的是,查一下你的 Perl是以系統內的 malloc
還是 Perl內含的 malloc
編譯起來的。不論是哪個,試著換成另一個,再看看這是否造成任何差別。關於
malloc的資訊可在 perl標準套件原始碼版中的 INSTALL
檔案找到。鍵入 perl
-V:usemymalloc
就可以知道你是否在使用 perl的 malloc。
sub makeone { my @a = ( 1 .. 10 ); return \@a; }
for $i ( 1 .. 10 ) { push @many, makeone(); }
print $many[4][5], "\n";
print "@many\n";
然而,在使用你的變數時,明智地用 my()
來定義執行範圍,可讓 Perl在脫離該範圍後
將它們所佔的空間釋放給其它部份的程式。 (註:my()的變數也比全域變數執行起來快
10%。)當然,一個全域變數永遠沒有超出範圍的時候,所以你無法將它佔用的空間自動重新分配,不過,把它 undef()
或/和 delete()
會有相同的效果。總之,在 Perl裡,你並不能/應該去擔心太多有關記憶體定址與解除這件事,而我們連添加這項功能(資料形態的預先定址),目前都已在進行中。
最起碼有兩種較流行的方法可以避免這些包袱。一種解法是將 mod_perl 或是 mod_fastcgi其中一個模組加在你所執行的 Apache HTTP server (可從 http://www.apache.org/取得)。有了 mod_perl 和 Apache::*模組 (從 CPAN取得),httpd執行時會帶起一個內 嵌的 Perl直譯器,而它會預先編譯你的程式,並在不產生其它子程序的情況下用同一個定址空間來執行。Apache 擴充模組亦給 Perl一個連通 server API 的管道,所以用 Perl寫的模組可以做到任何 C寫的模組所具備的功能。而有了 FCGI模組 (自 CPAN取得),你以 sfio (參看 perl標準套件原始碼版本中的 INSTALL檔案) 和 mod_fastcgi (從 http://www.fastcgi.com/取得)模組編譯成的 Perl 直譯器將使你的每個 perl程式變成一個固定的 CGI 背景程序 (daemon process)。
這些方法對你的系統與你撰寫 CGI程式的方法都有超乎想像之外的影響,所以請小心地 探索它們。
然而,首先,你 不能拿走讀取權,不然你的程式怎麼被解譯或是編譯呢? (不過那也並不表示一個 CGI程式的原始碼可以被使用者讀取。)所以你得讓檔案權限停留在 0755這個友善的階段。
有些人認為這是個安全上的漏洞。不過若你的程式作的是不安全的事情,光仰賴別人 看不見這些漏洞、不知從何下手,那麼它依然是不安全的。其實對有些人來說他們並 不需要看見程式原始碼便可能判定並揭露這些不安全的部份。透過隱瞞達到的安全, 就是不修正臭蟲反而隱藏它們,實際上是沒有安全性可言的。
你可以試著透過原始碼過濾模組 (CPAN中的 Filter::*)來替原始碼加密。但高手也許有 辦法將其解密還原。你也可以用下面提到的 byte code 編譯器與直譯器,但高手也有可能反解譯它。你可以試試後面提到的原生碼編譯器 (native-code compiler),但高手也有可 能反組譯它。這些手段都需要不同難度的技巧才能讓別人拿到你的原始碼,但沒有一種能 夠很確定地隱藏它。(這對每種語言來說都為真,不是只有 Perl)
如果你所擔心的是別人自你的程式碼中獲利,那麼一紙權限執照是能提供你法律上安全的唯一途徑。註冊你的軟體並且寫份權限說明,再加上一些具威脅性的句子像“這是 XYZ公司未出版的專有軟體。你能擷取它並不代表你具有使用的權限...”之類云云。當然,我們不是律師,所以若你想要你的執照中每一句話在法庭上都站得住腳,就去見個律師吧。
請了解光是編譯成 C 其本身或在本質上並不能保證它就會跑得快更多。那是因為除了 在運氣好的狀況中有一堆可以衍生成出來的原生形態外,平時的 Perl 執行系統環境依然 存在因此依然會花差不多長的執行時間與佔用差不多大小的記憶空間。大多數程式能省下 來的不過是編譯時間,這使執行速度頂多快 10-30%。有些罕見的程式能真正從中受利 (例如增快好幾倍),但這還得配合原始碼的微調。
Malcolm 將會主導 Perl 5.005 版的發展並試著將其編譯器與多執行緒部份的工作融合進主要的發行版本裡。
你或許會驚訝地發現,現行版本的編譯器做出來的執行檔大小跟你的 Perl直譯器一樣大,有時更大些。那是因為依照現在的寫法,所有的程式皆轉成一個被 eval()
的大敘述。只要建造一個動態連結的 libperl.so程式庫,並將之連結起來,你就可以戲劇性地減少這
種浪費。參看 perl原始碼套件中的
INSTALL pod檔案以獲得更詳盡的訊息。如果你用這方法連結你主要的 perl執行檔,就能使它變得很渺小。舉例來說,在作者之一的系
統裡, /usr/bin/perl只有 11k“小”而已!
extproc perl -S -your_switches
當作 *.cmd
檔案的第一行 (-S
是因 cmd.exe中其 `extproc'處理的臭蟲才要的)。DOS使用者應先製作一個相對的 batch
檔案然後將它以
ALTERNATIVE_SHEBANG
的方式寫成程式。(更多訊息在原始碼版本的 INSTALL檔案裡)
若安裝 Activeware版的 Win95/NT 專用 Perl,它會更動 Registry的內容,把 .pl 的擴充檔名與 perl直譯器結合。如果你安裝另一版本或是用 WinGCC建構你自己的 Win95/NT用 Perl,那你就得自己更動 Registry的內容了。
麥金塔的 perl程式將會有適當的創造者與形態 (Creator and Type),所以雙擊它們就會執行這些 perl 應用程式。
重要:不論你做什麼,請千萬不要因為覺得沮喪,就把 perl 直譯器丟到你的 cgi-bin目錄下,好讓你的 web 伺服器能執行你的程式。這是一個非常大的安全漏洞。花點時間想 想怎樣才是正確的做法吧。
#把第一欄和最後一欄相加 perl -lane 'print $F[0] + $F[-1]'
#辨別是否為文字檔 perl -le 'for(@ARGV) {print if -f && -T _}' *
#移除 C程式中的說明 perl -0777 -pe 's{/\*.*?\*/}{}gs' foo.c
#讓檔案年輕一個月,躲避追殺的魔鬼 (daemon) perl -e '$X=24*60*60; utime(time(),time() + 30 * $X,@ARGV)' *
#找出第一個未用的 uid perl -le '$i++ while getpwuid($i); print $i'
#顯示合理的使用說明路徑 (manpath) echo $PATH | perl -nl -072 -e ' s![^/+]*$!man!&&-d&&!$s{$_}++&&push@m,$_;END{print"@m"}'
好吧,最後一個例子事實上是「perl程式困惑化」競賽 (Obfuscated Perl)的 參賽作品。 :-)
例如說:
# Unix perl -e 'print "Hello world\n"'
# DOS,等。 perl -e "print \"Hello world\n\""
# Mac print "Hello world\n" (然後執行 "Myscript"或按 Shift-Command-R)
# VMS perl -e "print ""Hello world\n"""
問題是,這些方法沒有一個是完全可靠的:它都得看命令解譯器的臉色。在 Unix中,前兩者通常可以用。在 DOS下,兩者可能都沒有用。若 4DOS是命令解譯器,下面此法可能比 較有希望:
perl -e "print <Ctrl-x>"Hello world\n<Ctrl-x>""
在 Mac 下,端視你所用的環境為何。 MacPerl所附的 shell,或是 MPW, 其所支援的參數格式有不少都蠻像 Unix shells的,除了它自在地使用 Mac 的非 ASCII字元當成控制字元。
恐怕我得說這問題並沒有一般解。白話一點說,它真是一團亂。
[部份答案是由 Kenneth Albanowski 所提供的。]
The Idiot's Guide to Solving Perl/CGI Problems, by Tom Christiansen http://www.perl.com/perl/faq/idiots-guide.html
Frequently Asked Questions about CGI Programming, by Nick Kew ftp://rtfm.mit.edu/pub/usenet/news.answers/www/cgi-faq http://www3.pair.com/webthing/docs/cgi/faqs/cgifaq.shtml
Perl/CGI programming FAQ, by Shishir Gundavaram and Tom Christiansen http://www.perl.com/perl/faq/perl-cgi-faq.html
The WWW Security FAQ, by Lincoln Stein http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html
World Wide Web FAQ, by Thomas Boutell http://www.boutell.com/faq/
(譯者:上面第三份文件,Perl-CGI-FAQ的中譯版可在 http://2Ti.com/cgi-bin/2T/perl/perl-cgi-faq-chi/ 處取得。最後一份(WWW FAQ)的中譯版可自 http://www.acer.net/document/cwwwfaq/ 取得。)
make test TEST_VERBOSE=1
與 perl -V
輸出的報告。
perl program 2>diag.out splain [-v] [-p] diag.out
更改你的程式讓它替你解釋這些訊息也可以:
use diagnostics;
或
use diagnostics -verbose;
譯者:陳彥銘
中譯版著作權所有:陳彥銘、蕭百齡及兩隻老虎工作室。本中譯版遵守並使用與 原文版相同的使用條款發行。