你到 CPAN(見perlfaq2)找過了嗎?也許別人已經寫了某個模組可以解決你的 問題。你查過相關的說明文件了嗎 (man pages)?以下是一份概要的索引:
物件 (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) 所能作的動作。
基本上來說,沒有。Shell.pm模組 (是 perl 標準套件之一)只是叫 perl 將非 Perl語言的命令當作 shell的命令來試著執行看看罷了。perl原始碼套件中的 perlsh,功能簡易,也很無趣,不過仍可能是你所要的。
你用過-w
嗎?
你試過use strict
嗎?
你是否檢查過每個系統呼叫 (system call)所傳回的值?
讀了perltrap說明文件嗎?
你試過perldebug里所提到的 Perl除蟲器嗎?
你該自 CPAN抓取 Devel::DProf 模組,并且使用 perl 標準套件所附的 Benchmark.pm。 Benchmark.pm讓你測量程式碼的某部份在執行上所花的時間,而 Devel::DProf則詳細地替你分析哪一部份的程式用掉多少時間。
隨著新發行的 alpha版 Perl編譯器(它不在一般標準套件里)而來的 B::Xref模組可 以替你的 Perl程式制作 cross-reference報告。用法是:
perl -MO=Xref[,OPTIONS] foo.pl
C有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 ,但是碰到復雜的程式碼可能就不能全然令人滿意了。
有個簡單的在http://www.perl.com/CPAN/authors/id/TOMC/scripts/ptags.gz 也許符合你的需要。
在ftp://ftp.perl.com/pub/vi/toms.exrc有完整的 Tom Christiansen之 vi設定檔, 它是給 vi模擬器用的標準測試檔 (standard benchmark file)。它與 nvi配合得最好,巧的是,這個出自 Berkeley的編輯器也可以內嵌一個 Perl直譯器 --參看http://www.perl.com/CPAN/src/misc。
從大約 Emacs 19.22版 (version 19 patchlevel 22)起,已內含了 perl-mode.el及 perl 除蟲器的支援。它們應該會和標準的 Emacs 19版一起出貨。
在 perl原始碼的目錄下,你會找到一個叫作 ``emacs'' 的目錄,里面包括一個 cperl-mode 可以把程式中的關鍵字上色、提供內文相關的協助以及其它方便的功能。
注意:``main'foo''(其中的單引號)會讓 emacs的 perl-mode生病,并且會弄亂內 縮 (indentation) 與精華 (hilighting)。不過你本來就該用 ``main::foo''的 (譯者按: main'foo 是表示模組或 package的舊式寫法;新式的 [perl5的]寫法是 main::foo)。
CPAN里的 Curses模組提供了一個通往 curses 程式庫的動態載入物件模組介面。
Tk這個完全以 Perl 為基礎,物件導向化的介面,讓你不用學 Tcl也可以使用 Tk工具組。Sx則是 Athena Widget set專用的介面。兩者都可在 CPAN取得。
http://www.perl.com/CPAN/authors/id/SKUNZ/perlmenu.v4.0.tar.gz 是個以 curses為基礎的模組,可以達成你的要求。
若你的系統架構有支援的話,標準 perl 套件便應該有此功能(介由 DynaLoader 這個模組)。詳情請參看perlxstut 。
看下個問題。
最好是能設計一個較好的演算法 (algorithm),這通常會讓程式有大不相同的表現。 駱駝書第八章里有些你或許想知道的增進效率小技巧。
其它方法包括自動載入較少使用的 Perl 程式碼。請參看標準 perl 套件中的 AutoSplit及 AutoLoader模組的用法?;虍斈隳軘喽ǔ淌綀绦行实钠款i在何處時,用 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程式把編譯後的檔案格式存到硬碟里以加快執行的速度已經是老掉牙的手法了。它已不再是個可行的方法,因為這方法只有幾種平臺能用,況且它終究不是個治本之 道。
當問題變成時間與空間的交易時, Perl 幾乎總是用記憶體來幫忙解決問題。 Perl中的純量 (Scalar) 耗掉的記憶體比 C中的字串形態還多,陣列又更多, 更別談雜湊陣列了 (Hashes)。關於這一點,我們當然還有很多工作得作,近來發布的版本,已開始針對這些問題做改進了。例如, 5.004 版中, 重復的雜湊陣列索引值 (duplicate hash keys) 由使用它的雜湊陣列共用,這樣就不用再重新定份位置給它了。
在某些情況下,使用substr()
或vec()
來模擬陣列有很大的好處。例如,一個有上千 個布林代數值的陣列將占用至少 20,000位元組的空間,但是它可以被轉變為一個 125位元組的位元向量 (bit vector)以節省相當可觀的記憶體。標準套件中的 Tie::SubstrHash模組也能夠幫助特定形態的資料結構節省些記憶體。若你正在和一些特殊的資料結構奮戰 (例如,矩陣),用 C寫的模組所耗掉的記憶體可能低於同功能并用 Perl寫的模組。
另一件值得一試的是,查一下你的 Perl是以系統內的 malloc 還是 Perl內含的 malloc 編譯起來的。不論是哪個,試著換成另一個,再看看這是否造成任何差別。關於 malloc的資訊可在 perl標準套件原始碼版中的INSTALL 檔案找到。鍵入perl -V:usemymalloc
就可以知道你是否在使用 perl的 malloc。
不,Perl的資源回收 (garbage collection)系統會解決此問題。
sub makeone { my @a = ( 1 .. 10 ); return \@a; }
for $i ( 1 .. 10 ) { push @many, makeone(); }
print $many[4][5], "\n";
print "@many\n";
你無法這麼作。系統配置給程式的記憶體是覆水難收。這也是為何執行很長一段時間的 程式有時會重新執行 (re-exec)它們自己的原因。
然而,在使用你的變數時,明智地用my()
來定義執行范圍,可讓 Perl在脫離該范圍後 將它們所占的空間釋放給其它部份的程式。 (注:my()的變數也比全域變數執行起來快 10%。)當然,一個全域變數永遠沒有超出范圍的時候,所以你無法將它占用的空間自動重新分配,不過,把它 undef()
或/和delete()
會有相同的效果??傊?,在 Perl里,你并不能/應該去擔心太多有關記憶體定址與解除這件事,而我們連添加這項功能(資料形態的預先定址),目前都已在進行中。
除了使一般 Perl程式加快或縮小的平常手段外,一個 CGI 程式還有其他的顧慮。也許它每秒會被執行好幾次。每次它執行時,重新編譯所花的時間、加上定址所需的 1 MB以上的系統記憶體,就是一個大殺手。光是編譯成 C是沒啥幫助的 ,因為瓶頸在於整個程序開始時所負擔的包袱 (start-up overhead) 。
最起碼有兩種較流行的方法可以避免這些包袱。一種解法是將 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公司未出版的專有軟體。你能擷取它并不代表你具有使用的權限...”之類云云。當然,我們不是律師,所以若你想要你的執照中每一句話在法庭上都站得住腳,就去見個律師吧。
Malcolm Beattie已經寫了一個多功能的後端編譯器,可以從 CPAN取得,它就能做到這兩項功能。1997 年二月是 alpha測試版的最後幾個階段,這代表著若你是個程式設計 員而非尋找萬靈解藥的人,那麼參與其測試就會充滿趣味。
請了解光是編譯成 C 其本身或在本質上并不能保證它就會跑得快更多。那是因為除了 在運氣好的狀況中有一堆可以衍生成出來的原生形態外,平時的 Perl 執行系統環境依然 存在因此依然會花差不多長的執行時間與占用差不多大小的記憶空間。大多數程式能省下 來的不過是編譯時間,這使執行速度頂多快 10-30%。有些罕見的程式能真正從中受利 (例如增快好幾倍),但這還得配合原始碼的微調。
Malcolm 將會主導 Perl 5.005 版的發展并試著將其編譯器與多執行緒部份的工作融合進主要的發行版本里。
你或許會驚訝地發現,現行版本的編譯器做出來的執行檔大小跟你的 Perl直譯器一樣大,有時更大些。那是因為依照現在的寫法,所有的程式皆轉成一個被 eval()
的大敘述。只要建造一個動態連結的 libperl.so程式庫,并將之連結起來,你就可以戲劇性地減少這 種浪費。參看 perl原始碼套件中的INSTALL pod檔案以獲得更詳盡的訊息。如果你用這方法連結你主要的 perl執行檔,就能使它變得很渺小。舉例來說,在作者之一的系 統里, /usr/bin/perl只有 11k“小”而已!
OS/2下只要用:
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 伺服器能執行你的程式。這是一個非常大的安全漏洞?;c時間想 想怎樣才是正確的做法吧。
可以。詳情請看perlrun。以下有些范例 (假設用的是標準的 Unix shell引言規則)。
#把第一欄和最後一欄相加 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 shells 所作的解釋不同,而後者很不幸的是這些一行 perl 的生父。在某些系統,也許你得把單引號改成雙引號,但這卻是你萬萬 不可在 Unix或 Plan9系統上作的事。你也許還得把一個 %改成 %%。
例如說:
# 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 所提供的。]
就模組來說,去 CPAN抓 CGI 和 LWP 兩個模組。就書本來看,參考關於書那部份里特別和 web 相關的問題。若有與 web相關的疑難雜癥,像“為何我收到 500錯誤”或“它在命令列模式下跑得好好的,怎麼不能在瀏覽器下正常執行”時,請參看:
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/ 取得。)
perltoot是個好開始,然後你可以再參考perlobj 和perlbot。Perltoot直到 5.004版本才誕生,但你可以從http://www.perl.com/CPAN/doc/FMTEYEWTK/下取得 (pod、html,或 postscript 格式)。
若你要從 Perl程式呼叫 C,就自perlxstut開始向 perlxs ,xsubpp ,及perlguts前進。反之,則讀 perlembed ,perlcall ,及perlguts 。別忘了 你可以從各模組的作者如何寫他們的模組及解決他們的問題中學到很多。
自 CPAN 下載 ExtUtils::Embed 套件,然後執行 `make test'。如果測試成功,就一遍又一遍地讀那些 pod 說明檔案。若它失敗了,參看perlbug并送一份內有make test TEST_VERBOSE=1
與perl -V
輸出的報告。
perldiag有一份完整的 perl錯誤與警告訊息列表,并附有說明文字。你也可以用 splain程式 (伴隨 perl而來)去解釋這些錯誤訊息:
perl program 2>diag.out splain [-v] [-p] diag.out
更改你的程式讓它替你解釋這些訊息也可以:
use diagnostics;
或
use diagnostics -verbose;
此模組 (亦為標準 perl 套件之一部份)設計的目的是要替一個模組從一 Makefile.PL 中自動撰寫出一個 Makefile。詳情請看MakeMaker 。