物件 (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;
译者:陈彦铭
中译版着作权所有:陈彦铭、萧百龄及两只老虎工作室。本中译版遵守并使用与 原文版相同的使用条款发行。