title: understanding request per second on apache bench
body: <p>I am trying to understand the performance benefit gained by gevent, and wanted to measure this quantitatively. Based on <a href="https://stackoverflow.com/questions/333664/simple-long-polling-example-code">this SO answer</a> I created a simple django app that has a sleep for 3 seconds in a simple view. </p>
  
  <p>When I run gunicorn with 1 synchronous worker, I get predictable request per second of ~ 3 seconds when I check using firefox. When I open just one more browser, I can see that it takes a longer time ( ~ 3 * the number of browsers I open). The front facing server is nginx.</p>
  
  <p>My view:</p>
  
  <pre><code>def home(request,epoch):
      sleeptime = 3
      time.sleep(sleeptime);
      html = "&lt;html&gt;&lt;body&gt;%s &lt;/body&gt;&lt;/html&gt;" % str(float(time.time()) - float(epoch) / 1000)
      return HttpResponse(html)
  </code></pre>
  
  <p>However, when I run the following <code>ab</code> command 
      ab -r  -n 100 -c 100 <a href="http://ec2-compute-1.amazonaws.com/" rel="nofollow noreferrer">http://ec2-compute-1.amazonaws.com/</a></p>
  
  <p>with the following gunicorn command, </p>
  
  <pre><code>gunicorn --pythonpath=/home/ubuntu/webapps/testt -c /home/ubuntu/webapps/testt/gunicorn.conf.py testt.wsgi
  </code></pre>
  
  <p>I get the following results:</p>
  
  <pre><code>Concurrency Level:      100
  Time taken for tests:   7.012 seconds
  Complete requests:      100
  Requests per second:    14.26 [#/sec] (mean)
  Time per request:       7011.750 [ms] (mean)
  Time per request:       70.118 [ms] (mean, across all concurrent requests)
  Transfer rate:          40.53 [Kbytes/sec] received
  
  Connection Times (ms)
                min  mean[+/-sd] median   max
  Connect:       37  837 1487.4     98    3869
  Processing:     0 3475 913.2   3777    3890
  Waiting:        0 3467 911.2   3777    3889
  Total:       3141 4312 1150.1   3870    7011
  </code></pre>
  
  <p>How should I understand the behavior of (3 * browser connections) from the above results?</p>
  
  <p>So, if there is just one worker and 100 clients are connecting, it should really take around 100 * 3 = 300 seconds for the 100th connection (because the 100th connection will have to wait for all the others connections to finish) BTW, if I open up 3 browsers and connect, i takes about 9 seconds worst case, which makes sense I think :). So, my first question is, how come I get ~7 seconds for Time per request in the above <code>ab</code> results? I would expect it to be a lot more since only the first 2 connections take around 6 seconds, and all the nth concurrent connections will take n*3 seconds long to return.</p>
  
  <p>When I do not change the program, and just do this following:</p>
  
  <pre><code>gunicorn -k gevent --pythonpath=/home/ubuntu/webapps/testt -c /home/ubuntu/webapps/testt/gunicorn.conf.py testt.wsgi
  </code></pre>
  
  <p>and run the same <code>ab</code> command, I get the following (!):</p>
  
  <pre><code>Concurrency Level:      100
  Time taken for tests:   0.558 seconds
  Complete requests:      100
  Failed requests:        0
  Write errors:           0
  Total transferred:      255300 bytes
  HTML transferred:       241600 bytes
  Requests per second:    179.32 [#/sec] (mean)
  Time per request:       557.675 [ms] (mean)
  Time per request:       5.577 [ms] (mean, across all concurrent requests)
  Transfer rate:          447.06 [Kbytes/sec] received
  
  Connection Times (ms)
                min  mean[+/-sd] median   max
  Connect:       33   44   6.2     47      58
  Processing:    47  133  74.0    122     506
  Waiting:       46  132  74.2    122     506
  Total:         80  177  76.2    162     555
  </code></pre>
  
  <p>So the smallest time you'd take to finish a request is 3 seconds, but the above results indicate it take less than a second, which does not make sense.</p>
  
  <p>What am I missing?</p>
  
  <p>I have attached the client that is pinging the view (it is similar, but not exactly, the one listed in the SO questions linked above:</p>
  
  <pre><code>&lt;html&gt;
  &lt;head&gt;
      &lt;title&gt;BargePoller&lt;/title&gt;
      &lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;
  
      &lt;style type="text/css" media="screen"&gt;
        body{ background:#000;color:#fff;font-size:.9em; }
        .msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid}
        .old{ background-color:#246499;}
        .new{ background-color:#3B9957;}
      .error{ background-color:#992E36;}
      &lt;/style&gt;
  
      &lt;script type="text/javascript" charset="utf-8"&gt;
      function addmsg(type, msg){
          /* Simple helper to add a div.
          type is the name of a CSS class (old/new/error).
          msg is the contents of the div */
          $("#messages").append(
              "&lt;div class='msg "+ type +"'&gt;"+ msg +"&lt;/div&gt;"
          );
      }
  
      function waitForMsg(){
          /* This requests the url "msgsrv.php"
          When it complete (or errors)*/
         var currentdate = new Date();
          $.ajax({
  
  
              type: "GET",
              url: "server/" + currentdate.getTime() + "/",
  
              async: true, /* If set to non-async, browser shows page as "Loading.."*/
              cache: false,
              timeout:50000, /* Timeout in ms */
  
              success: function(data){ /* called when request to barge.php completes */
                  addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/
                  setTimeout(
                      waitForMsg, /* Request next message */
                      1000 /* ..after 1 seconds */
                  );
              },
              error: function(XMLHttpRequest, textStatus, errorThrown){
                  var currentdate = new Date();
                  addmsg("error", currentdate.getTime() + textStatus + " (" + errorThrown + " " + currentdate.getTime() + ")");
                  setTimeout(
                      waitForMsg, /* Try again after.. */
                      1000); /* milliseconds (15seconds) */
              },
           beforeSend: function(){
                 var currentdate = new Date();
                  addmsg("body", currentdate + " &lt;-  sent request");
              }
          });
      };
  
      $(document).ready(function(){
          waitForMsg(); /* Start the inital request */
      });
      &lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
      &lt;div id="messages"&gt;
          &lt;div class="msg old"&gt;
              BargePoll message requester!
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>