📄 ch17_01.htm
字号:
<blockquote><pre class="code">...while (<FILE>) { chomp; $count++; $some_large_array[$count] .= int ($_);}... @some_large_array = ( ); ## Goodundef @some_large_array; ## Not so good</pre></blockquote><p>If you undefine <tt class="literal">@some_large_array</tt> to clear it out,Perl will deallocate the space containing the data. And when youpopulate the array with new data, Perl will have to reallocate thenecessary space again. This can slow things down.</p></div><a name="ch17-6-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.6. SelfLoader</h3><p>The SelfLoader module <a name="INDEX-3229" /> <a name="INDEX-3230" /> <a name="INDEX-3231" /><a name="INDEX-3232" />allowsyou to hide <a name="INDEX-3233" /><a name="INDEX-3234" />functions and subroutines,so the Perl interpreter does not compile them into internal opcodeswhen it loads up your application, but compiles them only where thereis a need to do so. This can yield great savings, especially if yourprogram is quite large and contains many subroutines that may not allbe run for any given request.</p><p>Let's look at how to convert your program to use self-loading,and then we can look at the internals of how it works. Here's asimple framework:</p><blockquote><pre class="code">use SelfLoader;## step 1: subroutine stubssub one;sub two;...## your main body of code...## step 2: necessary/required subroutinessub one { ...}__DATA__## step 3: all other subroutinessub two { ...}...__END__</pre></blockquote><p>It's a three-step process:</p><ol><li><p>Create stubs for all the functions and subroutines in yourapplication.</p></li><li><p>Determine which functions are used often enough that they should beloaded by default.</p></li><li><p>Take the rest of your functions and move them between the <tt class="literal">__DATA__</tt> and <tt class="literal">__END__</tt> tokens.</p></li></ol><p>Congratulations, Perl will now load these functions only on demand!</p><p>Now, how does it actually work? The <tt class="literal">__DATA__</tt>token has a special significance to Perl; everything after the tokenis available for reading through the DATA filehandle. When Perlreaches the <tt class="literal">__DATA__</tt> token, it stops compiling,and all the subroutines defined after the token do not exist, as faras Perl is concerned.</p><p>When you call an unavailable function, SelfLoader reads in all thesubroutines from the DATA filehandle, and caches them in a hash. Thisis a one-time process, and is performed the first time you call anunavailable function. It then checks to see if the specified functionexists, and if so, will <tt class="function">eval</tt> it within thecaller's namespace. As a result, that function now exists inthe caller's namespace, and any subsequent calls to thatfunction are handled via symbol table lookups.</p><p>The costs of this process are the one time reading and parsing of theself-loaded subroutines, and a <tt class="function">eval</tt> for eachfunction that is invoked. Despite this overhead, the performance oflarge programs with many functions and subroutines can improvedramatically.</p></div><a name="ch17-7-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.7. autouse</h3><p>If you use many <a name="INDEX-3235" /><a name="INDEX-3236" /><a name="INDEX-3237" /><a name="INDEX-3238" />externalmodules in your application, you may consider using the<em class="emphasis">autouse</em> feature to delay loading them until aspecific function from a module is used:</p><blockquote><pre class="code">use autouse DB_File;</pre></blockquote><p>You have to be very careful when using this feature, since a portionof the chain of execution will shift from compile time to runtime.Also, if a module needs to execute a particular sequence of stepsearly on in the compile phase, using <em class="emphasis">autouse</em> canpotentially break your applications.</p><p>If the modules you need behave as expected, using<em class="emphasis">autouse</em> for modules can yield a big savings whenit comes time to "load" your application.</p></div><a name="ch17-8-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.8. Avoid the Shell</h3><p>Avoid accessing the <a name="INDEX-3239" /><a name="INDEX-3240" /><a name="INDEX-3241" />shell from yourapplication, unless you have no other choice. Perl has equivalentfunctions to many Unix commands. Whenever possible, use the functionsto avoid the shell overhead. For example, use the<em class="emphasis">unlink</em> function, instead of executing theexternal <tt class="command">rm</tt> command:</p><blockquote><pre class="code">system( "/bin/rm", $file ); ## External commandunlink $file or die "Cannot remove $file: $!"; ## Internal function</pre></blockquote><p>It as also much safer to avoid the shell, as we saw in <a href="ch08_01.htm">Chapter 8, "Security"</a>. However, there are some instances when youmay get better performance using some standard external programs thanyou can get in Perl. If you need to find all occurrences of a certainterm in a very large text file, it may be faster to use<tt class="command">grep</tt><a name="INDEX-3242" /><a name="INDEX-3243" /> than performing the same task in Perl:</p><blockquote><pre class="code">system( "/bin/grep", $expr, $file );</pre></blockquote><p>Note however, that the circumstances under which you might need to dothis are rare. First, Perl must do a lot of extra work to invoke asystem call, so the performance difference gained by an externalcommand is seldom worth the overhead. Second, if you only wereinterested in the first match and not all the matches, then Perlgains speed because your script can exit the loop as soon as it findsa match:</p><blockquote><pre class="code">my $match;open FILE, $file or die "Could not open $file: $!";while (<FILE>) { chomp; if ( /$expr/ ) { $match = $_; last; }}</pre></blockquote><p><tt class="command">grep</tt> will always read the entire file. Third, ifyou find yourself needing to resort to using <tt class="command">grep</tt>to handle text files, it likely means that the problem isn't somuch with Perl as with the structure of your data. You shouldprobably consider a different data format, such as a DBM file or aRDBMS.</p><p>Also avoid using the <a name="INDEX-3244" /><a name="INDEX-3245" /><a name="INDEX-3246" />glob<tt class="literal"><*></tt> notation to get a list of files in aparticular directory. Perl must invoke a subshell to expand this. Inaddition to this being inefficient, it can also be erroneous; certainshells have an internal glob limit, and will return files only up tothat limit. Note that Perl 5.6, when released, will solve theselimitations by handling globs internally.</p><p>Instead, use Perl's <tt class="function">opendir</tt>,<tt class="function">readdir,</tt> and <tt class="function">closedir</tt>functions. Here is an example:</p><blockquote><pre class="code">@files = </usr/local/apache/htdocs/*.html>; ## Uses the shell....$directory = "/usr/local/apache/htdocs"; ## A better solutionif (opendir (HTDOCS, $directory)) { while ($file = readdir (HTDOCS)) { push (@files, "$directory/$file") if ($file =~ /\.html$/); }}</pre></blockquote></div><a name="ch17-9-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.9. Find Existing Solutions for Your Problems</h3><p>Chances are, if you find <a name="INDEX-3247" /> <a name="INDEX-3248" /> <a name="INDEX-3249" />yourself stuck with aproblem, someone else has encountered it elsewhere and has spent alot of time developing a solution. And thanks to the spirit of Perl,you can likely borrow it. Throughout this book, we have referred tomany modules that are available on CPAN. There are countless more.Take the time to browse through CPAN regularly to see what isavailable there.</p><p>You should also check out the Perlnewsgroups. <em class="emphasis">news:comp.lang.perl.modules</em> is a goodplace to go to check in with new module announcements or to get helpwith particular modules. <em class="emphasis">news:comp.lang.perl</em> and<em class="emphasis">news:comp.lang.perl.misc</em> are more generalnewsgroups.</p><p>Finally, there are many very good books available that discussalgorithms or useful tricks and tips. The <em class="citetitle">PerlCookbook</em> by Tom Christiansen and Nathan Torkington and<em class="citetitle">Mastering Algorithms with Perl</em> by Jon Orwant,Jarkko Hietaniemi, and John Macdonald are full of gems specificallyfor Perl. Of course, don't overlook books whose focus is notPerl. <em class="citetitle">Programming Pearls</em> by John Bentley,<em class="citetitle">The C Programming Language</em> by Brian Kernighanand Dennis Ritchie, and <em class="citetitle">Code Complete</em> by SteveMcConnell are also all excellent references.</p></div><a name="ch17-10-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.10. Regular Expressions </h3><p>Regular <a name="INDEX-3250" /> <a name="INDEX-3251" /> <a name="INDEX-3252" />expressions are an integral part ofPerl, and we use them in many CGI applications. There are manydifferent ways that we can improve the performance of regularexpressions.</p><p>First, avoid using <tt class="literal">$&</tt>, <tt class="literal">$`</tt>,and <tt class="literal">$'</tt>. If Perl spots one of these variables inyour application, or in a module that you imported, it will make acopy of the search string for possible future reference. This ishighly inefficient, and can really bog down your application. You canuse the <a name="INDEX-3253" /><a name="INDEX-3254" /><a name="INDEX-3255" />Devel::SawAmpersand module, availableon CPAN, to check for these variables.</p><p>Second, the following type of regular expressions are highlyinefficient:</p><blockquote><pre class="code">while (<FILE>) { next if (/^(?:select|update|drop|insert|alter)\b/); ... }</pre></blockquote><p>Instead, use the following syntax:</p><blockquote><pre class="code">while (<FILE>) { next if (/^select/); next if (/^update/); ...}</pre></blockquote><p>Or, consider building a runtime compile pattern if you do not knowwhat you are searching against at compile time:</p><blockquote><pre class="code">@keywords = qw (select update drop insert);$code = "while (<FILE>) {\n";foreach $keyword (@keywords) { $code .= "next if (/^$keyword/);\n";}$code .= "}\n";eval $code;</pre></blockquote><p>This will build a code snippet that is identical to the one shownabove, and evaluate it on the fly. Of course, you will incur anoverhead for using <em class="emphasis">eval</em>, but you will have toweigh that against the savings you will gain.</p><p>Third, consider using <em class="emphasis">o</em> modifier in expressionsto compile the pattern only once. Take a look at this example:</p><blockquote><pre class="code">@matches = ( );...while (<FILE>) { push @matches, $_ if /$query/i;}...</pre></blockquote><p>Code like this is typically used to search for a string in a file.Unfortunately, this code will execute very slowly, because Perl hasto compile the pattern each time through the loop. However, you canuse the <em class="emphasis">o</em> modifier to ask Perl to compile theregex just once:</p><blockquote><pre class="code">push @matches, $_ if /$query/io;</pre></blockquote><p>If the value of <tt class="literal">$query</tt> changes in your script,this won't work, since Perl will use the first compiled value.The compiled regex features introduced in Perl 5.005 address this;refer to the <em class="citetitle">perlre</em> manpage for moreinformation.</p><p>Finally, there are often multiple ways that you can build a regularexpression for any given task, but some ways are more efficient thanothers. If you want to learn how to write more <a name="INDEX-3256" /> <a name="INDEX-3257" /> <a name="INDEX-3258" />efficient regularexpressions, <a name="INDEX-3259" /> <a name="INDEX-3260" /> <a name="INDEX-3261" />we highly <a name="INDEX-3262" /> <a name="INDEX-3263" />recommend Jeffrey Friedl's<em class="citetitle">Mastering Regular Expressions</em>.</p><p>These tips are general optimization tips. You'll get a lot ofmileage from some, and not so much from the others, depending on yourapplication. Now, it's time to look at more complicated ways tooptimize our CGI applications.</p></div></div><hr align="left" width="515" /><div class="navbar"><table border="0" width="515"><tr><td width="172" valign="top" align="left"><a href="ch16_02.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0" /></a></td><td width="171" valign="top" align="center"><a href="index.htm"><img src="../gifs/txthome.gif" alt="Home" border="0" /></a></td><td width="172" valign="top" align="right"><a href="ch17_02.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0" /></a></td></tr><tr><td width="172" valign="top" align="left">16.2. Coding Guidelines</td><td width="171" valign="top" align="center"><a href="index/index.htm"><img src="../gifs/index.gif" alt="Book Index" border="0" /></a></td><td width="172" valign="top" align="right">17.2. FastCGI</td></tr></table></div><hr align="left" width="515" /><img src="../gifs/navbar.gif" alt="Library Navigation Links" usemap="#library-map" border="0" /><p><font size="-1"><a href="copyrght.htm">Copyright © 2001</a> O'Reilly & Associates. All rights reserved.</font></p><map name="library-map"><area href="../index.htm" coords="1,1,83,102" shape="rect" /><area href="../lnut/index.htm" coords="81,0,152,95" shape="rect" /><area href="../run/index.htm" coords="172,2,252,105" shape="rect" /><area href="../apache/index.htm" coords="238,2,334,95" shape="rect" /><area href="../sql/index.htm" coords="336,0,412,104" shape="rect" /><area href="../dbi/index.htm" coords="415,0,507,101" shape="rect" /><area href="../cgi/index.htm" coords="511,0,601,99" shape="rect" /></map></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -