Sophie

Sophie

distrib > Fedora > 13 > x86_64 > by-pkgid > 552d72b401c5b4a5a4c52922e7b31f2c > files > 67

python-eventlet-doc-0.9.12-1.fc13.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>Design Patterns &mdash; Eventlet v0.9.12 documentation</title>
    <link rel="stylesheet" href="_static/default.css" type="text/css" />
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '',
        VERSION:     '0.9.12',
        COLLAPSE_MODINDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="_static/jquery.js"></script>
    <script type="text/javascript" src="_static/doctools.js"></script>
    <link rel="top" title="Eventlet v0.9.12 documentation" href="index.html" />
    <link rel="next" title="Greening The World" href="patching.html" />
    <link rel="prev" title="Basic Usage" href="basic_usage.html" /> 
  </head>
  <body>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="modindex.html" title="Global Module Index"
             accesskey="M">modules</a> |</li>
        <li class="right" >
          <a href="patching.html" title="Greening The World"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="basic_usage.html" title="Basic Usage"
             accesskey="P">previous</a> |</li>
        <li><a href="index.html">Eventlet v0.9.12 documentation</a> &raquo;</li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="design-patterns">
<span id="id1"></span><h1>Design Patterns<a class="headerlink" href="#design-patterns" title="Permalink to this headline">¶</a></h1>
<p>There are a bunch of basic patterns that Eventlet usage falls into.  Here are a few examples that show their basic structure.</p>
<div class="section" id="client-pattern">
<h2>Client Pattern<a class="headerlink" href="#client-pattern" title="Permalink to this headline">¶</a></h2>
<p>The canonical client-side example is a web crawler.  This use case is given a list of urls and wants to retrieve their bodies for later processing.  Here is a very simple example:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">urls</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;http://www.google.com/intl/en_ALL/images/logo.gif&quot;</span><span class="p">,</span>
       <span class="s">&quot;https://wiki.secondlife.com/w/images/secondlife.jpg&quot;</span><span class="p">,</span>
       <span class="s">&quot;http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif&quot;</span><span class="p">]</span>

<span class="kn">import</span> <span class="nn">eventlet</span>
<span class="kn">from</span> <span class="nn">eventlet.green</span> <span class="kn">import</span> <span class="n">urllib2</span>

<span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">urllib2</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>

<span class="n">pool</span> <span class="o">=</span> <span class="n">eventlet</span><span class="o">.</span><span class="n">GreenPool</span><span class="p">()</span>
<span class="k">for</span> <span class="n">body</span> <span class="ow">in</span> <span class="n">pool</span><span class="o">.</span><span class="n">imap</span><span class="p">(</span><span class="n">fetch</span><span class="p">,</span> <span class="n">urls</span><span class="p">):</span>
    <span class="k">print</span> <span class="s">&quot;got body&quot;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
</pre></div>
</div>
<p>There is a slightly more complex version of this in the <a class="reference external" href="examples.html#web-crawler-example"><em>web crawler example</em></a>.  Here&#8217;s a tour of the interesting lines in this crawler.</p>
<p><tt class="docutils literal"><span class="pre">from</span> <span class="pre">eventlet.green</span> <span class="pre">import</span> <span class="pre">urllib2</span></tt> is how you import a cooperatively-yielding version of urllib2.  It is the same in all respects to the standard version, except that it uses green sockets for its communication.  This is an example of the <a class="reference external" href="patching.html#import-green"><em>Import Green</em></a> pattern.</p>
<p><tt class="docutils literal"><span class="pre">pool</span> <span class="pre">=</span> <span class="pre">eventlet.GreenPool()</span></tt> constructs a <a title="eventlet.greenpool.GreenPool" class="reference external" href="modules/greenpool.html#eventlet.greenpool.GreenPool"><tt class="xref docutils literal"><span class="pre">GreenPool</span></tt></a> of a thousand green threads.  Using a pool is good practice because it provides an upper limit on the amount of work that this crawler will be doing simultaneously, which comes in handy when the input data changes dramatically.</p>
<p><tt class="docutils literal"><span class="pre">for</span> <span class="pre">body</span> <span class="pre">in</span> <span class="pre">pool.imap(fetch,</span> <span class="pre">urls):</span></tt> iterates over the results of calling the fetch function in parallel.  <a title="eventlet.greenpool.GreenPool.imap" class="reference external" href="modules/greenpool.html#eventlet.greenpool.GreenPool.imap"><tt class="xref docutils literal"><span class="pre">imap</span></tt></a> makes the function calls in parallel, and the results are returned in the order that they were executed.</p>
<p>The key aspect of the client pattern is that it involves collecting the results of each function call; the fact that each fetch is done concurrently is essentially an invisible optimization.  Note also that imap is memory-bounded and won&#8217;t consume gigabytes of memory if the list of urls grows to the tens of thousands (yes, we had that problem in production once!).</p>
</div>
<div class="section" id="server-pattern">
<h2>Server Pattern<a class="headerlink" href="#server-pattern" title="Permalink to this headline">¶</a></h2>
<p>Here&#8217;s a simple server-side example, a simple echo server:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">eventlet</span>

<span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="n">client</span><span class="p">):</span>
    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">c</span><span class="p">:</span> <span class="k">break</span>
        <span class="n">client</span><span class="o">.</span><span class="n">sendall</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>

<span class="n">server</span> <span class="o">=</span> <span class="n">eventlet</span><span class="o">.</span><span class="n">listen</span><span class="p">((</span><span class="s">&#39;0.0.0.0&#39;</span><span class="p">,</span> <span class="mi">6000</span><span class="p">))</span>
<span class="n">pool</span> <span class="o">=</span> <span class="n">eventlet</span><span class="o">.</span><span class="n">GreenPool</span><span class="p">(</span><span class="mi">10000</span><span class="p">)</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
    <span class="n">new_sock</span><span class="p">,</span> <span class="n">address</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">accept</span><span class="p">()</span>
    <span class="n">pool</span><span class="o">.</span><span class="n">spawn_n</span><span class="p">(</span><span class="n">handle</span><span class="p">,</span> <span class="n">new_sock</span><span class="p">)</span>
</pre></div>
</div>
<p>The file <a class="reference external" href="examples.html#echo-server-example"><em>echo server example</em></a> contains a somewhat more robust and complex version of this example.</p>
<p><tt class="docutils literal"><span class="pre">server</span> <span class="pre">=</span> <span class="pre">eventlet.listen(('0.0.0.0',</span> <span class="pre">6000))</span></tt> uses a convenience function to create a listening socket.</p>
<p><tt class="docutils literal"><span class="pre">pool</span> <span class="pre">=</span> <span class="pre">eventlet.GreenPool(10000)</span></tt> creates a pool of green threads that could handle ten thousand clients.</p>
<p><tt class="docutils literal"><span class="pre">pool.spawn_n(handle,</span> <span class="pre">new_sock)</span></tt> launches a green thread to handle the new client.  The accept loop doesn&#8217;t care about the return value of the <tt class="docutils literal"><span class="pre">handle</span></tt> function, so it uses <a title="eventlet.greenpool.GreenPool.spawn_n" class="reference external" href="modules/greenpool.html#eventlet.greenpool.GreenPool.spawn_n"><tt class="xref docutils literal"><span class="pre">spawn_n</span></tt></a>, instead of <a title="eventlet.greenpool.GreenPool.spawn" class="reference external" href="modules/greenpool.html#eventlet.greenpool.GreenPool.spawn"><tt class="xref docutils literal"><span class="pre">spawn</span></tt></a>.</p>
<p>The difference between the server and the client patterns boils down to the fact that the server has a <tt class="docutils literal"><span class="pre">while</span></tt> loop calling <tt class="docutils literal"><span class="pre">accept()</span></tt> repeatedly, and that it hands off the client socket completely to the handle() method, rather than collecting the results.</p>
</div>
<div class="section" id="dispatch-pattern">
<h2>Dispatch Pattern<a class="headerlink" href="#dispatch-pattern" title="Permalink to this headline">¶</a></h2>
<p>One common use case that Linden Lab runs into all the time is a &#8220;dispatch&#8221; design pattern.  This is a server that is also a client of some other services.  Proxies, aggregators, job workers, and so on are all terms that apply here.  This is the use case that the <a title="eventlet.greenpool.GreenPile" class="reference external" href="modules/greenpool.html#eventlet.greenpool.GreenPile"><tt class="xref docutils literal"><span class="pre">GreenPile</span></tt></a> was designed for.</p>
<p>Here&#8217;s a somewhat contrived example: a server that receives POSTs from clients that contain a list of urls of RSS feeds.  The server fetches all the feeds concurrently and responds with a list of their titles to the client.  It&#8217;s easy to imagine it doing something more complex than this, and this could be easily modified to become a Reader-style application:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">eventlet</span>
<span class="n">feedparser</span> <span class="o">=</span> <span class="n">eventlet</span><span class="o">.</span><span class="n">import_patched</span><span class="p">(</span><span class="s">&#39;feedparser&#39;</span><span class="p">)</span>

<span class="n">pool</span> <span class="o">=</span> <span class="n">eventlet</span><span class="o">.</span><span class="n">GreenPool</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">fetch_title</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
    <span class="n">d</span> <span class="o">=</span> <span class="n">feedparser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">d</span><span class="o">.</span><span class="n">feed</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;title&#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
    <span class="n">pile</span> <span class="o">=</span> <span class="n">eventlet</span><span class="o">.</span><span class="n">GreenPile</span><span class="p">(</span><span class="n">pool</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">url</span> <span class="ow">in</span> <span class="n">environ</span><span class="p">[</span><span class="s">&#39;wsgi.input&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">readlines</span><span class="p">():</span>
        <span class="n">pile</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="n">fetch_title</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
    <span class="n">titles</span> <span class="o">=</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">pile</span><span class="p">)</span>
    <span class="n">start_response</span><span class="p">(</span><span class="s">&#39;200 OK&#39;</span><span class="p">,</span> <span class="p">[(</span><span class="s">&#39;Content-type&#39;</span><span class="p">,</span> <span class="s">&#39;text/plain&#39;</span><span class="p">)])</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">titles</span><span class="p">]</span>
</pre></div>
</div>
<p>The full version of this example is in the <a class="reference external" href="examples.html#feed-scraper-example"><em>Feed Scraper</em></a>, which includes code to start the WSGI server on a particular port.</p>
<p>This example uses a global (gasp) <a title="eventlet.greenpool.GreenPool" class="reference external" href="modules/greenpool.html#eventlet.greenpool.GreenPool"><tt class="xref docutils literal"><span class="pre">GreenPool</span></tt></a> to control concurrency.  If we didn&#8217;t have a global limit on the number of outgoing requests, then a client could cause the server to open tens of thousands of concurrent connections to external servers, thereby getting feedscraper&#8217;s IP banned, or various other accidental-or-on-purpose bad behavior.  The pool isn&#8217;t a complete DoS protection, but it&#8217;s the bare minimum.</p>
<p>The interesting lines are in the app function:</p>
<div class="highlight-python"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">pile</span> <span class="o">=</span> <span class="n">eventlet</span><span class="o">.</span><span class="n">GreenPile</span><span class="p">(</span><span class="n">pool</span><span class="p">)</span>
<span class="k">for</span> <span class="n">url</span> <span class="ow">in</span> <span class="n">environ</span><span class="p">[</span><span class="s">&#39;wsgi.input&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">readlines</span><span class="p">():</span>
    <span class="n">pile</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="n">fetch_title</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
<span class="n">titles</span> <span class="o">=</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">pile</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Note that in line 1, the Pile is constructed using the global pool as its argument.  That ties the Pile&#8217;s concurrency to the global&#8217;s.  If there are already 1000 concurrent fetches from other clients of feedscraper, this one will block until some of those complete.  Limitations are good!</p>
<p>Line 3 is just a spawn, but note that we don&#8217;t store any return value from it.  This is because the return value is kept in the Pile itself.  This becomes evident in the next line...</p>
<p>Line 4 is where we use the fact that the Pile is an iterator.  Each element in the iterator is one of the return values from the fetch_title function, which are strings.  We can use a normal Python idiom (<tt class="xref docutils literal"><span class="pre">join()</span></tt>) to concatenate these incrementally as they happen.</p>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
            <h3><a href="index.html">Table Of Contents</a></h3>
            <ul>
<li><a class="reference external" href="#">Design Patterns</a><ul>
<li><a class="reference external" href="#client-pattern">Client Pattern</a></li>
<li><a class="reference external" href="#server-pattern">Server Pattern</a></li>
<li><a class="reference external" href="#dispatch-pattern">Dispatch Pattern</a></li>
</ul>
</li>
</ul>

            <h4>Previous topic</h4>
            <p class="topless"><a href="basic_usage.html"
                                  title="previous chapter">Basic Usage</a></p>
            <h4>Next topic</h4>
            <p class="topless"><a href="patching.html"
                                  title="next chapter">Greening The World</a></p>
            <h3>This Page</h3>
            <ul class="this-page-menu">
              <li><a href="_sources/design_patterns.txt"
                     rel="nofollow">Show Source</a></li>
            </ul>
          <div id="searchbox" style="display: none">
            <h3>Quick search</h3>
              <form class="search" action="search.html" method="get">
                <input type="text" name="q" size="18" />
                <input type="submit" value="Go" />
                <input type="hidden" name="check_keywords" value="yes" />
                <input type="hidden" name="area" value="default" />
              </form>
              <p class="searchtip" style="font-size: 90%">
              Enter search terms or a module, class or function name.
              </p>
          </div>
          <script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="modindex.html" title="Global Module Index"
             >modules</a> |</li>
        <li class="right" >
          <a href="patching.html" title="Greening The World"
             >next</a> |</li>
        <li class="right" >
          <a href="basic_usage.html" title="Basic Usage"
             >previous</a> |</li>
        <li><a href="index.html">Eventlet v0.9.12 documentation</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer">
      &copy; Copyright 2005-2010, Eventlet Contributors.
      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.6.
    </div>
  </body>
</html>