⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch17_01.htm

📁 用perl编写CGI的好书。本书从解释CGI和底层HTTP协议如何工作开始
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<?label 17. Efficiency and Optimization?><html><head><title>Efficiency and Optimization (CGI Programming with Perl)</title><link href="../style/style1.css" type="text/css" rel="stylesheet" /><meta name="DC.Creator" content="Scott Guelich, Gunther Birznieks and Shishir Gundavaram" /><meta scheme="MIME" content="text/xml" name="DC.Format" /><meta content="en-US" name="DC.Language" /><meta content="O'Reilly & Associates, Inc." name="DC.Publisher" /><meta scheme="ISBN" name="DC.Source" content="1565924193L" /><meta name="DC.Subject.Keyword" content="stuff" /><meta name="DC.Title" content="CGI Programming with Perl" /><meta content="Text.Monograph" name="DC.Type" /></head><body bgcolor="#ffffff"><img src="gifs/smbanner.gif" alt="Book Home" usemap="#banner-map" border="0" /><map name="banner-map"><area alt="CGI Programming with Perl" href="index.htm" coords="0,0,466,65" shape="rect" /><area alt="Search this book" href="jobjects/fsearch.htm" coords="467,0,514,18" shape="rect" /></map><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">CGI Programming with Perl</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></table></div><hr align="left" width="515" /><h1 class="chapter">Chapter 17. Efficiency and Optimization</h1><div class="htmltoc"><h4 class="tochead">Contents:</h4><p><a href="ch17_01.htm">Basic Perl Tips, Top Ten</a><br><a href="ch17_02.htm">FastCGI</a><br><a href="ch17_03.htm">mod_perl</a><br></p></div><p>Let's face it, <a name="INDEX-3188" /> <a name="INDEX-3189" /> <a name="INDEX-3190" />CGI applications, run under normalconditions, are not exactly speed demons. In this chapter, we willshow you a few tricks that you can use to speed up currentapplications, and also introduce you to twotechnologies -- FastCGI and <em class="emphasis">mod_perl</em> -- that allow you to develop significantly acceleratedCGI applications. If you develop Perl CGI scripts on Win32, then youmay also wish to look at<a name="INDEX-3191" /> <a name="INDEX-3192" />ActiveState's PerlEx. Although wedo not discuss PerlEx in this chapter, it provides many of the samebenefits as <em class="emphasis">mod_perl</em>.</p><p>First, let's try to understand why CGI applications are so<a name="INDEX-3193" />slow. When a user requests aresource from a web server that turns out to be a CGI application,the server has to create another process to handle the request. Andwhen you're dealing with applications that use<a name="INDEX-3194" />interpreted languages, like Perl, there isan additional delay incurred in firing up the interpreter, thenparsing and compiling the application.</p><p>So, how can we possibly improve the performance of Perl CGIapplications? We could ask Perl to interpret only the most commonlyused parts of our application, and delay interpreting other piecesunless necessary. That certainly would speed up applications. Or, wecould turn our application into a server (<a name="INDEX-3195" /><a name="INDEX-3196" />daemon) that runs in thebackground and executes on demand. We would no longer have to worryabout the overhead of firing up the<a name="INDEX-3197" /><a name="INDEX-3198" />interpreter andevaluating the code. Or, we could embed the Perl interpreter withinthe web server itself. Again, we avoid the overhead of having tostart a new process, and we don't even suffer the communicationdelay we would have talking to another daemon.</p><p>We'll look at all the techniques mentioned here, in addition tobasic Perl tips for writing more efficient applications. Let'sstart with the basics.</p><div class="sect1"><a name="ch17-30424" /><h2 class="sect1">17.1. Basic Perl Tips, Top Ten</h2><p>Here is a list of ten techniques you <a name="INDEX-3199" /> <a name="INDEX-3200" /> <a name="INDEX-3201" />can use to <a name="INDEX-3202" /> <a name="INDEX-3203" />improve the performance of your CGIscripts:</p><blockquote class="simplelist"><p>10.  Benchmark your code.</p><p>9.  Benchmark modules, too.</p><p>8.  Localize variables with <tt class="function">my.</tt></p><p>7.  Avoid slurping data from files.</p><p>6.  Clear arrays with <tt class="function">undef</tt> instead of <tt class="literal">()</tt>.</p><p>5.  Use <em class="emphasis">SelfLoader</em> where applicable.</p><p>4.  Use <em class="emphasis">autouse</em> where applicable.</p><p>3.  Avoid the shell.</p><p>2.  Find existing solutions for your problems.</p><p>1.  Optimize your regular expressions.</p></blockquote><p>Let's look at each one in more detail.</p><a name="ch17-1-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.1. Benchmark Your Code</h3><p>Before we <a name="INDEX-3204" /><a name="INDEX-3205" /> <a name="INDEX-3206" />can determine how well our program isworking, we need to know how to benchmark the critical code.Benchmarking may sound involved, but all it really involves is timinga piece of code, and there are some standard Perl modules to makethis very easy to perform. Let's look at a few ways tobenchmark code, and you can choose the one that works best for you.</p><p>First, here's the simplest way to benchmark:</p><blockquote><pre class="code">$start = (times)[0];## your code goes here$end = (times)[0];printf "Elapsed time: %.2f seconds!\n", $end - $start;</pre></blockquote><p>This determines the elapsed user time needed to execute your code inseconds. It is important to consider a few rules when benchmarking:</p><ul><li><p>Try to benchmark only the relevant piece(s) of code.</p></li><li><p>Don't accept the first benchmark value. Benchmark the codeseveral times and take the average.</p></li><li><p>If you are comparing different benchmarks, make sure they are testedunder comparable conditions. For example, make sure that the load onthe machine doesn't differ between tests because another userhappened to be running a heavy job during one.</p></li></ul><p>Second, we can use the Benchmark module. The Benchmark moduleprovides us with several functions that allow us to compare multiplepieces of code and determine elapsed CPU time as well as elapsedreal-world time.</p><p>Here's the easiest way to use the module:</p><blockquote><pre class="code">use Benchmark;$start = new Benchmark;## your code goes here$end = new Benchmark;$elapsed = timediff ($end, $start);print "Elapsed time: ", timestr ($elapsed), "\n";</pre></blockquote><p>The result will look similar to the following:</p><blockquote><pre class="code">Elapsed time:  4 wallclock secs (0.58 usr +  0.00 sys =  0.58 CPU)</pre></blockquote><p>You can also use the module to benchmark several pieces of code. Forexample:</p><blockquote><pre class="code">use Benchmark;timethese (100, {                    for =&gt; &lt;&lt;'end_for',                        my   $loop;                        for ($loop=1; $loop &lt;= 100000; $loop++) { 1 }end_for                    foreach =&gt; &lt;&lt;'end_foreach'                        my      $loop;                        foreach $loop (1..100000) { 1 }end_foreach                } );</pre></blockquote><p>Here, we are checking the <em class="emphasis">for</em> and<em class="emphasis">foreach</em> loop constructs. As a side note, youmight be interested to know that, in cases where the loop iterator isgreat, <em class="emphasis">foreach</em> is much less efficient than<em class="emphasis">for</em> in versions of Perl older than 5.005.</p><p>The resulting output of <tt class="function">timethese</tt> will looksomething like this:</p><blockquote><pre class="code">Benchmark: timing 100 iterations of for, foreach...       for: 49 wallclock secs (49.07 usr +  0.01 sys = 49.08 CPU)   foreach: 69 wallclock secs (68.79 usr +  0.00 sys = 68.79 CPU)</pre></blockquote><p>One thing to note here is that Benchmark uses the<em class="emphasis">time</em> system call to perform the actual timing,and therefore the granularity is still limited to one second. If youwant higher resolution timing, you can experiment with theTime::HiRes module. Here's an example of how to use the module:</p><blockquote><pre class="code">use Time::HiRes;my $start = [ Time::HiRes::gettimeofday(  ) ];## Your code goes heremy $elapsed = Time::HiRes::tv_interval( $start );print "Elapsed time: $elapsed seconds!\n";</pre></blockquote><p>The <tt class="function">gettimeofday</tt> function returns the currenttime in seconds and microseconds; we place these in a list, and storea reference to this list in <tt class="literal">$start</tt>. Later, afterour code has run, we call <tt class="function">tv_interval</tt>, whichtakes <tt class="literal">$start</tt> and calculates the difference betweenthe original time and the current time. It returns a floating-pointnumber indicating the number of seconds elapsed.</p><p>One caveat: the less time your code takes, the less reliable yourbenchmarks will be. Time::HiRes can be useful for determining howlong portions of your program take to run, but do not use it if youwant to compare two subroutines that each take less than one second.When comparing code, it is better to use Benchmark and have it testyour subroutines <a name="INDEX-3207" /> <a name="INDEX-3208" /> <a name="INDEX-3209" />over many iterations.</p></div><a name="ch17-2-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.2. Benchmark Modules, Too</h3><p>CPAN is <a name="INDEX-3210" /><a name="INDEX-3211" />absolutelywonderful. It contains a great number of highly useful Perl modules.You should take advantage of this resource because the code availableon CPAN has been tested and improved by the entire Perl community.However, if you are creating applications where performance iscritical, remember to benchmark code included from modules you areusing in addition to your own. For example, if you only need aportion of the functionality available in a module, you may benefitby deriving your own version of the module that is tuned for yourapplication. Most modules distributed on CPAN are available accordingto the same terms as Perl, which allows you to modify code withoutrestriction for your own internal use. However, be sure to verify thelicensing terms for a module before you do this, and if you believeyour solution would be beneficial to others, notify the moduleauthor, and please give back to CPAN.</p><p>You should also determine whether using a module make sense. Forexample, a popular module is IO::File, which provides a set offunctions to deal with file I/O:</p><blockquote><pre class="code">use IO::File;$fh = new IO::File;if ($fh-&gt;open ("index.html")) {    print &lt;$fh&gt;;    $fh-&gt;close;}</pre></blockquote><p>There are advantageous to using an interface like IO::File.Unfortunately, due to module loading and method-call overhead, thiscode is, on the average, ten times slower than:</p><blockquote><pre class="code">if (open FILE, "index.html") {    print &lt;FILE&gt;;    close FILE;}</pre></blockquote><p>So the bottom line is, pay very careful attention to modules that youuse.</p></div><a name="ch17-3-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.3. Localize Variables with my</h3><p>You should <a name="INDEX-3212" /> <a name="INDEX-3213" /><a name="INDEX-3214" /> <a name="INDEX-3215" />create lexical variables with the<tt class="function">my</tt><a name="INDEX-3216" /> function. Perl keeps track ofmanaging memory usage for you, but it doesn't look ahead to seeif you are going to use a variable in the future. In order to createa variable that you need only within a particular block of code, suchas a subroutine, declare it with <tt class="function">my</tt>. Then thememory for that variable will be reclaimed at the end of the block.</p><p>Note that despite its name, the<em class="emphasis">local</em><a name="INDEX-3217" /> function doesn't localizevariables in the standard sense of the term. Here is an example:</p><blockquote><pre class="code">sub name {    local $my_name = shift;    greeting(  );}sub greeting {    print "Hello $my_name, how are you!\n";}</pre></blockquote><p>If you run this simple program, you can see that<tt class="literal">$my_name</tt> isn't exactly local to the<tt class="function">name</tt> function. In fact, it is also visible in<tt class="function">greeting</tt>. This behavior can produce unexpectedresults if you are not careful. Thus, most Perl developers avoidusing <tt class="function">local</tt> and use <tt class="function">my</tt>instead for everything except global variables, file handles, andPerl's built-in global punctuation variables like<tt class="literal">$_</tt> or <tt class="literal">$/</tt>.</p></div><a name="ch17-4-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.4. Avoid Slurping</h3><p>What is slurping, you ask? <a name="INDEX-3218" /> <a name="INDEX-3219" /> <a name="INDEX-3220" /> <a name="INDEX-3221" />Consider the following code:</p><blockquote><pre class="code">local $/;open FILE, "large_index.html" or die "Could not open file!\n";$large_string = &lt;FILE&gt;;close FILE;</pre></blockquote><p>Since we undefine the input record separator, one read on the filehandle will<em class="emphasis">slurp</em><a name="INDEX-3222" /><a name="INDEX-3223" /> (or read in) the entire file. Whendealing with large files, this can be highly inefficient. If what youare doing can be done a line at a time, then use a<tt class="function">while</tt> loop to process only a line at a time:</p><blockquote><pre class="code">open FILE, "large_index.html" or die "Could not open file!\n";while (&lt;FILE&gt;) {    # Split fields by whitespace, output as HTML table row    print $q-&gt;tr( $q-&gt;td( [ split ] ) );}close FILE;</pre></blockquote><p>Of course, there are situations when you cannot process a line at atime. For example, you may be looking for data that crosses lineboundaries. In this case, you may fall back to slurping for smallfiles. Try benchmarking your code to see what kind of penalty isimposed by slurping in the entire file.</p></div><a name="ch17-5-fm2xml" /><div class="sect2"><h3 class="sect2">17.1.5. undef Versus (  )</h3><p>If you intend to reuse<a name="INDEX-3224" /><a name="INDEX-3225" />arrays, <a name="INDEX-3226" /><a name="INDEX-3227" /><a name="INDEX-3228" />especiallylarge ones, it is more efficient to clear them out by equating themto a null list instead of undefining them. For example:</p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -