<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Curia</title>
	<atom:link href="http://blog.curiasolutions.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.curiasolutions.com</link>
	<description>Technology thoughts and ideas</description>
	<lastBuildDate>Tue, 21 Aug 2012 14:57:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>An rsync-like utility for Amazon S3 and Google Storage</title>
		<link>http://blog.curiasolutions.com/2011/12/an-rsync-like-utility-for-amazon-s3-and-google-storage/</link>
		<comments>http://blog.curiasolutions.com/2011/12/an-rsync-like-utility-for-amazon-s3-and-google-storage/#comments</comments>
		<pubDate>Mon, 12 Dec 2011 00:55:06 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[boto]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=1101</guid>
		<description><![CDATA[Every so often I find myself working on that odd job that requires syncing files with Amazon&#8217;s S3. In the beginning, I tried some of the various S3 FUSE interfaces—hoping for something that would play nice with rsync—but FUSE&#8217;s stability always left something to be desired and more often than not I&#8217;d be left with [...]]]></description>
			<content:encoded><![CDATA[<p>Every so often I find myself working on that odd job that requires syncing files with Amazon&#8217;s S3. In the beginning, I tried some of the various S3 FUSE interfaces—hoping for something that would play nice with rsync—but FUSE&#8217;s stability always left something to be desired and more often than not I&#8217;d be left with that one transfer that never would quite finish correctly.</p>
<p>Eventually I discovered <a href="http://github.com/boto/boto" target="_blank">boto</a> and settled in to using a hacked together (but stable) Python/boto solution for these type of tasks—all the while wondering why nobody took the time to write a &#8220;real&#8221; rsync-like client for S3.</p>
<p>Well, this last time around I finally decided to stop whining and take matters into my own hands. After a couple of late nights fleshing out my original boto solution, I&#8217;m happy to announce what I&#8217;m calling &#8220;boto rsync&#8221;—an rsync like wrapper for boto&#8217;s cloud storage interfaces (both S3 <em>and</em> Google Storage).</p>
<p>Please take a look at the project on github and let me know what you think: <a href="http://github.com/seedifferently/boto_rsync" target="_blank">http://github.com/seedifferently/boto_rsync</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2011/12/an-rsync-like-utility-for-amazon-s3-and-google-storage/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>The long overdue &#8220;Shootout&#8221; update</title>
		<link>http://blog.curiasolutions.com/2011/09/the-long-overdue-shootout-update/</link>
		<comments>http://blog.curiasolutions.com/2011/09/the-long-overdue-shootout-update/#comments</comments>
		<pubDate>Mon, 12 Sep 2011 19:08:06 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[pylons]]></category>
		<category><![CDATA[pyramid]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[turbogears]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=1079</guid>
		<description><![CDATA[It&#8217;s been several months since I&#8217;ve had a chance to update The Great Web Framework Shootout, but this weekend I decided that it was time to dig in and freshen things up a bit. Not only have most of the frameworks seen new releases since the last revision, but I finally decided to move all [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been several months since I&#8217;ve had a chance to update <em><a title="The Great Web Framework Shootout" href="http://blog.curiasolutions.com/the-great-web-framework-shootout/">The Great Web Framework Shootout</a></em>, but this weekend I decided that it was time to dig in and freshen things up a bit.</p>
<p>Not only have most of the frameworks seen new releases since the last revision, but I finally decided to move all of the tests over to Amazon&#8217;s &#8220;release&#8221; version of the Ubuntu LTS AMI.</p>
<p>Below is a quick summary of what&#8217;s new in this revision:</p>
<ul>
<li>All tests were performed on the updated Ubuntu LTS AMI (ami-fbbf7892 ubuntu-images-us/ubuntu-lucid-10.04-amd64-server-20110719.manifest.xml)</li>
<li>The updated AMI was configured with Python 2.6.5, PHP 5.3.2, Ruby 1.9.2p290, Apache 2.2.14 (default config), mod_wsgi 2.8 (embedded mode), and mod_passenger 3.0.9</li>
<li>Rails 2.x and 3.0 were dropped from the &#8220;full stack(ish)&#8221; tests in favor of Rails 3.1.</li>
<li>CakePHP 1.2 was dropped from the PHP tests in favor of 1.3, but Symfony and Yii were added as they seem to have considerable market share.</li>
<li>CakePHP&#8217;s caching engine was incorrectly configured during the last round of tests, and this has been corrected.</li>
</ul>
<p><a href="http://profiles.google.com/seedifferently" target="_blank">Circle me on Google+</a> to keep track of further updates, and feel free to contact me there with any questions or comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2011/09/the-long-overdue-shootout-update/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Google+: It&#8217;s a bigger deal than Facebook, but not like you think</title>
		<link>http://blog.curiasolutions.com/2011/07/google-its-a-bigger-deal-than-facebook-but-not-like-you-think/</link>
		<comments>http://blog.curiasolutions.com/2011/07/google-its-a-bigger-deal-than-facebook-but-not-like-you-think/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 01:53:41 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[social]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=1048</guid>
		<description><![CDATA[I&#8217;ve been on Google+ since week 1 and while the initial mood has been overwhelmingly positive, I couldn&#8217;t help but notice the content of my stream becoming a bit skewed over the past few days as Google began opening it up more and more to &#8220;the laypeople.&#8221; Google was wise to restrict G+&#8217;s initial membership [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been on Google+ since week 1 and while the initial mood has been overwhelmingly positive, I couldn&#8217;t help but notice the content of my stream becoming a bit skewed over the past few days as Google began opening it up more and more to &#8220;the laypeople.&#8221; Google was wise to restrict G+&#8217;s initial membership base to the tech-savvy, because we&#8217;re already on to Google about where it&#8217;s going with this thing; but now that the rest of the world is jumping onboard there seems to be a bit of confusion about what it&#8217;s good for.</p>
<p>In response to this, I thought I&#8217;d share a few of my own thoughts on G+, and why I believe it is a valuable and needed addition the online social ecosystem:</p>
<blockquote>
<div>1. It&#8217;s not Facebook, and it&#8217;s not Twitter—it&#8217;s a bit of both, and the key is Circles.</div>
</blockquote>
<p>What Twitter does best is giving busy professionals, celebrities, and business entities an outlet to interact <em>publicly</em> with their audience on a pseudo-personal level <em>in 140 characters or less</em>. What Facebook does best is giving people an outlet to interact <em>somewhat privately</em> with <em>people they trust</em> on as personal of a level as they like. For many, the separation between Twitter vs. Facebook mirrors their own separation of business vs. personal. For example: A picture of your 2-year old squeezing the cat is more likely to wind up posted to a <em>limited audience</em> on Facebook than publicly shared on Twitter, while a quick blurb updating <em>anyone interested</em> on a recent professional achievement often <em>needs</em> a more public forum such as Twitter to gain the visibility you want it to have. Even in each of their post boxes you can see the difference in what&#8217;s expected to be shared: Twitter asks &#8220;What&#8217;s happening?&#8221; expecting you to want the whole world to know, while Facebook asks &#8220;What&#8217;s on your mind?&#8221; which is quite a bit more personal. <span id="more-1048"></span></p>
<p>What Google+ gives you is both (and much more), through the power of a brilliant feature called Circles. No longer is it a question of public vs. private, but rather the much more honest and straightforward &#8221;Who do you want to share this with?&#8221; Through Circles, you now have complete control over who will and who wont see the content you are about to share. You may only want &#8220;close friends&#8221; to see how crazy that party was last night, while &#8220;friends&#8221; can be given access to pictures of your recent vacation to Hawaii, and <em>the whole world</em> can have access to that presentation you did last week that received a standing ovation.</p>
<p>(Note: Yes I am aware that Facebook offers something similar to Circles, but its integration is clumsy and inconvenient in comparison.)</p>
<blockquote><p>2. For now, it may only be relevant to those who manage multiple online identities.</p></blockquote>
<p>Sure, there are plenty of people who use Twitter and Facebook as practically the same outlet, and if you&#8217;re one of those then Google+ is probably going to be little more than a redundant nuisance—one more social network to have to keep track of.</p>
<p>Or perhaps you&#8217;re the Facebook-only or Twitter-only type and simply don&#8217;t see the point in jumping ship or picking up another service. I applaud you for your loyalty, but in this day and age resistance to &#8220;the big G&#8221; is futile. Which leads me to my final thought&#8230;</p>
<blockquote><p>3. If you can look to the horizon, it might just be bigger than anything we&#8217;ve seen yet!</p></blockquote>
<p>The real thing to keep in mind in these early days is that G+ is just the beginning of Google&#8217;s plan to bring a social element to many of its products and services. In the coming months, you are probably going to see the google.com ecosystem revolve more and more tightly around G+ to a point where involvement in the + will be unavoidable. They have already somewhat merged Picasa and there are whispers of a full-on integration with Gmail. What else could be coming? Well, just think about all of the services that Google currently offers and simply add a &#8220;+&#8221; to them: Music+, Calendar+, Maps+, Docs+, Checkout+, etc.—and I&#8217;m not even going to take the time here to mention Android and the possible mobile implications!</p>
<p>But what about speculative projects? Well, Google recently sank loads of cash into a little company called Zynga and not too long ago partnered with Rovio to bring Angry Birds to Chrome. Can you imagine playing &#8220;Words With Friends+&#8221; or &#8220;Angry Birds+&#8221; online with all your G+ friends?</p>
<p>The future of Google is here folks, and it&#8217;s as subtle as a +.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2011/07/google-its-a-bigger-deal-than-facebook-but-not-like-you-think/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The great web technology shootout – Round 4: Pyramid vs Django vs TG vs Rails 2 &amp; 3</title>
		<link>http://blog.curiasolutions.com/2010/11/the-great-web-technology-shootout-%e2%80%93-round-4-pyramid-vs-django-vs-tg-vs-rails-2-3/</link>
		<comments>http://blog.curiasolutions.com/2010/11/the-great-web-technology-shootout-%e2%80%93-round-4-pyramid-vs-django-vs-tg-vs-rails-2-3/#comments</comments>
		<pubDate>Fri, 19 Nov 2010 00:00:06 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[pyramid]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[turbogears]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=915</guid>
		<description><![CDATA[[Note: Due to the popularity of these posts, I have decided to move all of the benchmarking information over to its own dedicated page. Please see the new framework shootout page for the latest information.] [This post is the continuation of a series. Please read Round 1, Round 2, and Round 3 first if you are [...]]]></description>
			<content:encoded><![CDATA[<p><strong><em>[Note: Due to the popularity of these posts, I have decided to move all of the benchmarking information over to its own dedicated page. Please see the new <a href="http://blog.curiasolutions.com/?p=963">framework shootout page</a> for the latest information.]</em></strong></p>
<p>[This post is the continuation of a series. Please read <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>, <a href="http://blog.curiasolutions.com/?p=278">Round 2</a>, and <a href="http://blog.curiasolutions.com/?p=409">Round 3</a> first if you are just now joining us.]</p>
<p>While I had originally intended for round 4 to showcase how microframeworks are changing the way we do &#8220;quick and dirty&#8221; web development (and how they make using PHP as &#8220;an extension to HTML&#8221; old hat), my current programming habits have kept me involved in the more &#8220;full-stack&#8221; framework solutions. So, rather than spitting out various benchmarks of frameworks that I have little or no interaction with, and since enough time has passed since the last &#8220;shootout&#8221; that the landscape has changed a bit (with the introduction of <a href="http://docs.pylonshq.com/" target="_blank">Pyramid</a> and the release of Rails 3), I have instead decided to showcase the most recent data on the frameworks that I personally find myself in contact with on a regular basis. <span id="more-915"></span></p>
<p>&nbsp;</p>
<blockquote>
<h4>Warning: Everything is different this time around!</h4>
</blockquote>
<p>These benchmarks were all run on a fresh Amazon EC2 instance in order to (hopefully) achieve a more isolated environment. Obviously, since these benchmarks have all been run on a completely different box than any of the previous rounds, no previous data should be compared with these numbers.</p>
<p><strong>What you should know about Round 4:</strong></p>
<ul>
<li>The EC2 instance used was: ami-da0cf8b3 m1.large ubuntu-images-us/ubuntu-lucid-10.04-amd64-server-20101020.manifest.xml</li>
<li>As a &#8220;Large&#8221; instance, Amazon describes the resources as: 7.5 GB of memory, 4 EC2 Compute Units (2 virtual cores with 2 EC2 Compute Units each), 850 GB of local instance storage, 64-bit platform.</li>
<li>The various system software used was whatever was current as of November 18, 2010 on Ubuntu 10.04&#8242;s repositories.</li>
<li>Apache 2.2.14 was used for all tests.</li>
<li>Python 2.6.5 and mod_wsgi 3.3 (embedded mode) were used for the Python tests.</li>
<li>Ruby 1.8.7 (except for the last Rails 3 test) and Phusion Passenger 3.0 were used for the Rails tests.</li>
<li>ApacheBench was run with -n 10000 and -c 10 about 5-10 times each, and the &#8220;best guess average&#8221; was chosen (yeah, I&#8217;m lazy).</li>
<li>The Pyramid/TG test apps used SQLAlchemy as the ORM and Jinja2 as the templating system (Jinja2 was consistently around 25-50r/s faster than Mako for me).</li>
</ul>
<p>&nbsp;</p>
<p>Remember, nothing here is really all that scientific and your mileage WILL vary. Now on to the results&#8230;</p>
<p>&nbsp;</p>
<blockquote>
<h4>The &#8220;Hello World&#8221; string test</h4>
</blockquote>
<p>The &#8220;Hello World&#8221; string test simply spits out a string response. There&#8217;s no template or DB calls involved, so the level of processing should be minimal.</p>
<div id="attachment_534" class="wp-caption aligncenter" style="width: 566px"><a href="http://blog.curiasolutions.com/wp-content/uploads/2010/11/round_4_hello.png"><img class="size-full wp-image-531" title="Hello World Test" src="http://blog.curiasolutions.com/wp-content/uploads/2010/11/round_4_hello.png" alt="The return hello world test chart" width="556" height="344" /></a><p class="wp-caption-text">The return hello world test chart</p></div>
<p>&nbsp;</p>
<blockquote>
<h4>The template test</h4>
</blockquote>
<p>The template test simply spits out Lorem Ipsum via a template (thus engaging the framework&#8217;s templating systems).</p>
<div id="attachment_535" class="wp-caption aligncenter" style="width: 566px"><a href="http://blog.curiasolutions.com/wp-content/uploads/2010/11/round_4_hellos.png"><img class="size-full wp-image-531" title="The template test chart" src="http://blog.curiasolutions.com/wp-content/uploads/2010/11/round_4_hellos.png" alt="The template test chart" width="556" height="344" /></a><p class="wp-caption-text">The template test chart</p></div>
<p>&nbsp;</p>
<blockquote>
<h4>The template + DB query test</h4>
</blockquote>
<p>The template/db test simply loads 5 rows of Lorem Ipsum from a SQLite DB and spits it out via a template (thus engaging both the framework&#8217;s ORM and templating system).</p>
<div id="attachment_536" class="wp-caption aligncenter" style="width: 566px"><a href="http://blog.curiasolutions.com/wp-content/uploads/2010/11/round_4_hellodb.png"><img class="size-full wp-image-531" title="Template test with database query" src="http://blog.curiasolutions.com/wp-content/uploads/2010/11/round_4_hellodb.png" alt="Template test with database query" width="556" height="344" /></a><p class="wp-caption-text">Template test with database query</p></div>
<p>&nbsp;</p>
<blockquote>
<h4>Closing thoughts</h4>
</blockquote>
<ul>
<li>The Pyramid Alpha results excite me quite a bit with all the talk of the various frameworks looking to merge with it. Could this really become the &#8220;one Python framework to rule them all&#8221;?</li>
<li>Django is still going strong, and continues to be an exceptional choice if you&#8217;re in to its way of doing things.</li>
<li>The Rails results <del datetime="2010-11-19T08:35:10+00:00">left me a little confused</del> are interesting because Rails 2 apparently outperforms Rails 3 on Ruby 1.8. Of course, once you move to Ruby 1.9, Rails 3 runs quite nicely.</li>
<li>Don&#8217;t believe these numbers? Feel free to boot up your own EC2 instance and run one of the test apps:
<ul>
<li><a href="http://blog.curiasolutions.com/wp-content/uploads/2010/11/pyramid.zip">Pyramid 1.0a3 test app code</a></li>
<li><a href="http://blog.curiasolutions.com/wp-content/uploads/2010/11/django.zip">Django 1.2 test app code</a></li>
<li><a href="http://blog.curiasolutions.com/wp-content/uploads/2010/11/tg21.zip">TurboGears 2.1 test app code</a></li>
<li><a href="http://blog.curiasolutions.com/wp-content/uploads/2010/11/rails3.zip">Rails 3 test app code</a></li>
<li><a href="http://blog.curiasolutions.com/wp-content/uploads/2010/11/rails2.zip">Rails 2 test app code</a></li>
</ul>
</li>
</ul>
<p>&nbsp;</p>
<p><strong>(Please don&#8217;t leave benchmarking requests as comments. If you&#8217;d like me to take a look at your favorite framework, direct message me on twitter. Thanks!)</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2010/11/the-great-web-technology-shootout-%e2%80%93-round-4-pyramid-vs-django-vs-tg-vs-rails-2-3/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Facts, FUD and Fanboys: Why I&#8217;ve chosen Android over the iPhone</title>
		<link>http://blog.curiasolutions.com/2010/09/android-the-iphone-facts-vs-fud/</link>
		<comments>http://blog.curiasolutions.com/2010/09/android-the-iphone-facts-vs-fud/#comments</comments>
		<pubDate>Tue, 28 Sep 2010 22:39:15 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[mobile]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=766</guid>
		<description><![CDATA[I&#8217;m not sure if anyone else&#8217;s world is like mine, but I work, eat, sleep, and breathe in a culture where Apple is king and the iPhone is the only phone. While I love Apple&#8217;s computers as much as the next guy (I always suggest that friends buy a Mac), I just don&#8217;t understand everyone&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m not sure if anyone else&#8217;s world is like mine, but I work, eat, sleep, and breathe in a culture where Apple is king and the iPhone is <em>the only</em> phone. While I love Apple&#8217;s <em>computers</em> as much as the next guy (I always suggest that friends buy a Mac), I just don&#8217;t understand everyone&#8217;s extraordinary love affair with the iPhone. Sure, it&#8217;s awfully nice to look at and it has definitely raised the bar for what it means to be a mobile device, but at the end of the day your device is only as valuable as the enhanced productivity it is capable of providing. If there are issues or limitations to a device&#8217;s ability to enhance productivity, wouldn&#8217;t you be wary of such a device?</p>
<p>Well, I am the black sheep in my culture because I have an Android phone. This sometimes causes a bit of a stir with co-workers and friends (all in good fun though, right?), but every now and then I come across someone who is thinking about upgrading phones and wants to know why I&#8217;ve chosen Android over the iPhone. The answer is actually quite simple in my mind, and basically comes down to what I would consider the three &#8220;killjoy&#8221; facts about the iPhone:</p>
<p><span id="more-766"></span></p>
<blockquote><p>Fact #1: The iPhone is part of a &#8220;closed ecosystem&#8221;</p></blockquote>
<p>Non-techies will probably see the phrase &#8220;closed ecosystem&#8221; and dismiss it as tech jargon and quickly move on to the next point; but in my mind this is probably the most important issue of them all, and it actually has a much larger affect on the end-user than most people realize. (I won&#8217;t even start about how this affects the developers. That could be a whole blog post of its own!)</p>
<p>So, what exactly do I mean by a &#8220;closed ecosystem&#8221; and how does it affect the end-user? In my opinion, this is best described in an over-simplified and somewhat silly little story:</p>
<blockquote><p>Bob decides one day to go and buy a ~$500 ultra-mobile computing device from Steve. Bob loves how sleek and sexy his new device is, but whenever Bob wants to install a new program on his new device, Bob has to check-in with Steve and make sure Steve is okay with Bob installing that program. Bob isn&#8217;t given the option to install whatever he wants whenever he wants—he always has to go through whatever process has been set up to gain Steve&#8217;s approval in order to install anything.</p></blockquote>
<p>That sounds kind of silly doesn&#8217;t it? We typically expect to have the freedom to do anything we like with something we&#8217;ve bought for ourselves; and yet, this is exactly how the iPhone&#8217;s integration with the Apple App Store works. While most people might laugh at the idea of this being much of an issue (the App Store certainly doesn&#8217;t <em>feel</em> very restrictive to the uninformed), it actually <em>is</em> a <a href="http://www.saurik.com/id/12" target="_blank">pretty big deal to some people</a>, and it&#8217;s why the word &#8220;<a href="http://en.wikipedia.org/wiki/IOS_jailbreaking" target="_blank">jailbreak</a>&#8221; has become a household word for many Apple extremists.</p>
<p>So, how does this play out in the real world for the end-user? Well, to be fair, let me first highlight the fact that there can be some &#8220;pluses&#8221; (depending on how you look at it) to a more restrictive system. For one, Steve can make sure Bob never installs a &#8220;bad&#8221; program on his device (of course, Steve decides what &#8220;bad&#8221; means). Also, by acting as the sole party in charge of &#8220;authorizing&#8221; applications (and therefore the gateway-*cough*-bottleneck between the app developers and their customers), Steve can create all kinds of developer requirements based on what&#8217;s important to him (aesthetics, functionality, etc), thus raising the bar of what <em>kind</em> of apps are created for his device. (Of course, this also causes <a href="http://techcrunch.com/2009/11/11/joe-hewitt-developer-of-facebooks-massively-popular-iphone-app-quits-the-project/" target="_blank">headache</a> after <a href="http://www.businessinsider.com/adidas-gives-up-on-apples-iads-because-steve-jobs-is-too-much-of-a-control-freak-scuttlebutt-2010-10" target="_blank">headache</a> for the developers; but I promised I wouldn&#8217;t get into that here&#8230;)</p>
<p>That sounds nice right—but what happens if your good ol&#8217; buddy Steve decides he doesn&#8217;t like a certain program anymore, even if it is widely used and <a href="http://www.adobe.com/products/player_census/flashplayer/" target="_blank">supported by 99% of the market</a>? I&#8217;m sure you iPhone users reading this have encountered <a href="http://www.walyou.com/blog/2010/04/15/no-flash-support-iphone-ipad/" target="_blank">this fun little image</a> before. Yeah, Steve decided that Flash was &#8220;not cool&#8221; and has therefore decreed that it will forever be banned from iOS devices. Or how about something a little more offbeat? Wouldn&#8217;t you love to have <a href="http://www.youtube.com/watch?v=pLOrr_-twwA" target="_blank">this awesome little text-input app</a> on your iPhone? Well, sorry guys, applications that ask for that much core integration with the OS aren&#8217;t cool either according to Steve, so tough luck! In fact, Steve won&#8217;t even give you <a href="http://www.youtube.com/watch?v=dBQFXRW5ZiE#t=04m26s" target="_blank">tethering</a>! Now where&#8217;s the fun in that (especially if you travel as much as I do)? Sure, farts are cool. And birds hitting pigs? Yeah, that&#8217;s cool too. But at the end of the day, Steve has the final say. Not you.</p>
<p>Remember: You paid to use your iPhone how <em>Steve</em> wants you to use it, not necessarily how <em>you</em> want to use it.</p>
<blockquote><p>Fact #2: The iPhones (yes, even the 3GS!) really do have reception issues</p></blockquote>
<p>While I agree with the Apple fanboys that &#8220;antennagate&#8221; was blown <em>way</em> out of proportion, I would still argue that as a <em>phone</em>, the iPhone sucks. Most people have been too busy blaming AT&amp;T (see my next point) to accept the truth, but the fact of the matter is that studies have shown that the iPhone <a href="http://www.pcworld.com/article/203914/iphone_great_device_lousy_telephone.html" target="_blank">has poorer reception than other leading AT&amp;T phones</a>. Yes, you read that right—AT&amp;T might not have as much to do with your dropped calls as you may think.</p>
<p>And how about that &#8220;revolutionary new antenna design&#8221; in the iPhone 4 that Mr. Jobs kept going on about? Well, do you remember <a href="http://www.engadget.com/2010/07/16/apple-iphone-4-drops-less-than-one-additional-call-per-100-tha/" target="_blank">this slide</a> from the epic &#8220;antennagate&#8221; emergency press meeting? According to &#8220;call drop data from AT&amp;T&#8221; the iPhone 4 actually drops <em>more</em> calls than the 3GS. Oops!</p>
<blockquote><p>Fact #3: AT&amp;T has some serious issues with its network in many areas</p></blockquote>
<p>It&#8217;s no secret that AT&amp;T&#8217;s network has issues. Over the past 10 years I&#8217;ve had contracts with all four major carriers and AT&amp;T was definitely the worst in terms of call reliability. After switching back to a carrier other than AT&amp;T, I think I&#8217;ve only had <em>one</em> dropped call so far <em>this entire year</em> (as opposed to what sometimes felt like every other call on AT&amp;T). What a novel idea: having a complete conversation without ever having to hit redial!</p>
<p>But I don&#8217;t even live in a major metropolitan area where AT&amp;T&#8217;s network is over-saturated. Did you know that <a href="http://arstechnica.com/apple/news/2009/09/poll-technica-iphone-dropped-callsis-30-normal-defesible.ars" target="_blank">the <em>average</em> dropped call rate for NYC is 30%</a> (according to a September 2009 report)? I would find that absolutely unacceptable.</p>
<p>Oh, and don&#8217;t keep holding your breath, the iPhone <a href="http://tech.fortune.cnn.com/2010/09/23/ceo-ivan-seidenberg-pours-cold-water-on-verizon-iphone-rumor/" target="_blank">still doesn&#8217;t seem to be coming to Verizon</a> anytime soon.</p>
<blockquote><p>But, isn&#8217;t Android susceptible to these issues as well?</p></blockquote>
<p>Without going into too much detail, the answer is both &#8220;no&#8221; and &#8220;maybe.&#8221;</p>
<p>The biggest difference is the ecosystem. Since Android is deeply rooted in <a href="http://en.wikipedia.org/wiki/Open_source" target="_blank">open source</a>, both the developers and the end-users are given an incredible amount of freedom to do whatever they want with their devices. This freedom has spawned a thriving &#8220;aftermarket&#8221; community that has gifted us with such marvels as <a href="http://en.wikipedia.org/wiki/CyanogenMod" target="_blank">custom ROMs</a>, <a href="http://www.appbrain.com/" target="_blank">3rd party app stores</a>, and all combinations of <a href="http://code.google.com/p/adw-launcher-android/" target="_blank">tweaks</a>, <a href="http://www.engadget.com/2010/09/29/confirmed-droid-2-hack-brings-fm-radio-in-one-ear-and-out-the/" target="_blank">tricks</a> and <a href="http://lifehacker.com/5653345/install-a-front+facing-camera-on-a-samsung-galaxy-s" target="_blank">enhancements</a>. But have no fear—if you&#8217;re someone who doesn&#8217;t like to get his or her feet wet pushing the bounds of your freedom, Google still has you covered with its own app store for an &#8220;official&#8221; application install channel.</p>
<p>Of course, any phone can have antenna issues (something Mr. Jobs has been clear to point out), so it would be nice to see data on dropped calls for a comparable Android phone on AT&amp;T&#8217;s network. However, the nice thing about the fact that Android is an <em>operating system</em> and not a phone (remember: the <em>Droid</em> is a phone and <em>Android</em> is the operating system that it and many other Android phones run) is that there are Android devices available on pretty much *every* mobile carrier of any size <a href="http://www.google.com/phone/" target="_blank">in the US</a> and all over the world.</p>
<blockquote><p>But the iPhone 4 still blows Android out of the water feature and spec wise, right?</p></blockquote>
<p>Actually, no. There are Android phones out there with more memory and processing power, higher resolution cameras (on the front and back), better battery life, and more vibrant displays (although &#8220;Retina&#8221; vs SuperAMOLED is probably still a personal preference thing).</p>
<p>Okay, I know what you&#8217;re thinking now: &#8220;What about FaceTime?&#8221; Well, the truth is that Android was doing face-to-face mobile video calls <em>before the iPhone 4 was even announced</em>. Crazy right? Well, here&#8217;s something else Apple probably doesn&#8217;t want you to know: Not only can you use an Android device to have FaceTime-like video chats with both iPhone 4 users and other Android users, but you also aren&#8217;t restricted to WiFi-only usage!</p>
<p>Oh, and remember: &#8220;successfully placing calls&#8221; should probably be pretty high up on your feature-list for a smart<em>phone</em>.</p>
<blockquote><p>&#8220;I Don&#8217;t Care! I Want An iPhone 4!&#8221;</p></blockquote>
<p>At the end of the day though, most people approach choosing a phone in much the same way as if they were choosing a watch or a new pair of sunglasses—it&#8217;s all about what looks good to them. The iPhone has an aura about it that is beautiful and sexy; and evidentially many people either do all of their phone talking within excellent AT&amp;T coverage areas (somewhere out there I&#8217;m sure such a thing exists), or they really don’t mind having calls drop on them. After all, you can always just hit redial, right? The overwhelming response by most iPhone fans to the issues I&#8217;ve raised above is either denial, or an emphatic &#8221;<a href="http://www.youtube.com/watch?v=FL7yD-0pqZg" target="_blank">I Don&#8217;t Care</a>&#8221; (warning: lots of NSFW language in that hilarious youtube video).</p>
<p>And why should they care? After all, <a href="http://www.wired.com/gadgetlab/2010/08/gadget-sex/" target="_blank">they have an iPhone</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2010/09/android-the-iphone-facts-vs-fud/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python as a PHP replacement?</title>
		<link>http://blog.curiasolutions.com/2009/11/python-as-a-php-replacement/</link>
		<comments>http://blog.curiasolutions.com/2009/11/python-as-a-php-replacement/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 18:11:50 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=637</guid>
		<description><![CDATA[I recently sat down to coffee with a new acquaintance of mine who spends much of his time implementing F/OSS projects at non-profit organizations, and who had just stepped into a lead web developer position using PHP. After sharing pleasantries we began trading stories and talking about each of our &#8220;tools of the trade.&#8221; When [...]]]></description>
			<content:encoded><![CDATA[<p>I recently sat down to coffee with a new acquaintance of mine who spends much of his time implementing F/OSS projects at non-profit organizations, and who had just stepped into a lead web developer position using PHP. After sharing pleasantries we began trading stories and talking about each of our &#8220;tools of the trade.&#8221; When I mentioned that I used to do most of my web development in PHP, but have spent the past year or so trying to move as completely as possible to Python, his response was: &#8220;Huh, I have never really thought of Python as a PHP replacement.&#8221;</p>
<p>Now, this guy hasn&#8217;t exactly been living under a rock for the past 10 years—his resume was quite impressive and included projects in a number of different programming languages; But as you can imagine, I was rather surprised by his response, and it made me wonder: Has the Python community really been that bad at promoting the strengths of Python for web development? Or, does the nirvana experienced by switching from a language like PHP to Python just make us so at peace with the world that we forget the hordes of developers still stuck with C-style syntax? Either way, it got me thinking about a few of the reasons why <em>I</em> decided to switch from PHP to Python; and why I not only see Python as an excellent PHP replacement, but am surprised it is such a &#8220;best-kept secret&#8221; for web development.</p>
<p>There are already plenty of pages out there discussing <a href="http://wiki.python.org/moin/PythonVsPhp" target="_blank">Python vs. PHP as a language</a>, so I probably won&#8217;t get too technical here. I also want to try avoid turning this into a &#8220;Python is better than PHP because&#8230;&#8221; rant (for more on that, please see the end of this post), so I will simply share with you a few of the main reasons why <em>I</em> decided to replace PHP with Python as <em>my</em> primary language for web development:</p>
<p><span id="more-637"></span></p>
<h4>» Python is more flexible than PHP</h4>
<p>Python was engineered from the beginning to be a general purpose programming language. PHP on the other hand was written to overcome many of the &#8220;limitations&#8221; of the <a href="http://en.wikipedia.org/wiki/Cgi-bin" target="_blank">cgi-bin</a>. This should say a lot about the &#8220;soul&#8221; of each language, but the conclusion I have come to is:</p>
<ul>
<li>PHP is meant to do web things really well</li>
<li>Python is meant to do most things really well</li>
</ul>
<p>Sure, these days you <em>could</em> write a desktop GUI in PHP, but it would most likely <em>not</em> be the right tool for the job (and you&#8217;d probably get laughed at). On a somewhat related note: many PHP developers I know find themselves switching between PHP for their website tasks, and a variety of other languages for other tasks (Shell Scripting for command-line scripts, Perl for text processing, etc.). As a Python programmer, I can typically stick to <em>one programming language</em> no matter what the task at hand requires (especially when armed with <a href="http://ipython.scipy.org/" target="_blank">iPython</a>).</p>
<p>Now, the obvious argument for PHP at this point is: &#8220;But wait, since PHP was written specifically for the web, shouldn&#8217;t that actually give it <em>more</em> credibility as the right tool for the web job?&#8221; Well, 5 or 10 years ago I might have agreed with you, but web development has changed a lot in the past few years (not to mention the introduction of Python&#8217;s <a href="http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface" target="_blank">WSGI spec</a>).</p>
<p>The internet as a platform has grown and mutated drastically and now requires much more than &#8220;a server-side extension to HTML.&#8221; We are now in an age of full-blown internet <em>applications</em>, which require a true &#8220;application-level&#8221; language. In my opinion, PHP has only recently begun to move in that direction with the v5.3 release (as well as updates expected in PHP 6). That alone should give you pause when pondering PHP&#8217;s ability to &#8220;keep up&#8221; with the growth of the web.</p>
<p>In short, the internet continues to transform into an arena that is much less of a website platform, and much more of an application platform. To me, this makes a general purpose language such as Python the obvious choice for &#8220;future-proof&#8221; internet development.</p>
<h4>» Python is typically faster than PHP, <span style="text-decoration: line-through;">even</span> especially on the web</h4>
<p>You might find PHP beating out Python in a simple &#8220;hello world&#8221;-type test, but &#8220;real-world&#8221; applications will typically run much faster in Python. In a Web 2.0 world where everyone has broadband, speed is now an important factor in keeping your visitors happy.</p>
<p>In addition to &#8220;raw, under-the-hood&#8221; speed, Python&#8217;s language philosophy means it will typically <a href="http://groups.google.com/group/comp.lang.python/msg/83907b65bdee30f6" target="_blank">scale better than PHP</a> (although this can be argued a million different ways, since scalability usually involves much more than the language).</p>
<p>I&#8217;ve already done <a href="http://blog.curiasolutions.com/2009/09/the-great-web-development-shootout/" target="_blank">benchmarks</a> comparing a few popular web frameworks, but if you&#8217;re still curious I&#8217;d suggest you <a href="http://www.google.com/search?q=is+python+or+php+faster%3F" target="_blank">dig around with Google</a> for a while.</p>
<h4>» Python is easier to read and maintain than PHP</h4>
<p>Any veteran programmer will tell you that code <em>readability</em> plays a huge factor in code <em>maintainability</em>. With that in mind, Python was designed with some pretty strict syntax rules in regards to code-blocks and whitespace. While this may initially frustrate programmers who are used to a looser &#8220;bracket-encapsulated&#8221; language, it actually forces you to write more readable (and therefore, more maintainable) code.</p>
<p>Other than readability, Python&#8217;s clean syntax also means:</p>
<ul>
<li>You can write more code with less errors (because they&#8217;re so easy to spot). This often comes as a pleasant surprise to programmers migrating from C-style languages (take <a href="http://www.python.org/about/success/esr/" target="_blank">Eric Raymond</a> for example).</li>
<li>You end up typing less — No more semicolons or brackets, and fewer parentheses.</li>
<li>Your eyes don&#8217;t have to move around as much to figure out what&#8217;s going on.</li>
<li>Your first guess about what&#8217;s happening in a code-block is usually correct.</li>
</ul>
<p>When you have time to kill, I&#8217;d recommend a stroll through <a href="http://rosettacode.org/wiki/Main_Page" target="_blank">Rosetta Code</a> to compare how different languages &#8220;look&#8221; when tackling the same problem. Unless you just love brackets, I think you&#8217;ll find the non C-style syntaxes much easier to read.</p>
<h4>» Python is more consistent than PHP</h4>
<p>Continuing somewhat in the vein of readability is the topic of consistency. Since PHP&#8217;s lack of consistency has already been studied exhaustively by the Perl folks, I will spare you my rant and suggest you <a href="http://tnx.nl/php.html" target="_blank">read theirs</a>.</p>
<p>As a side note on this topic: I often hear PHP programmers talk about how awesome PHP&#8217;s documentation is in that you can open a web browser and just type &#8220;php.net/some_function&#8221; to get help. Well, documentation recall usually isn&#8217;t that big of a deal for me (because I have a somewhat photographic memory), but I will say that after switching to Python I found myself turning to its documentation <em>significantly</em> less than I had with PHP, simply because I didn&#8217;t have to keep reminding myself whether that infrequently used function was named some_function or somefunction. With Python, the function/method I need is usually named <em>exactly</em> what I expect it to be named, and returns <em>exactly</em> what I expect it to return.</p>
<p>Oh, and don&#8217;t even get me started on PHP&#8217;s recent <a href="http://blog.fedecarg.com/2008/10/28/php-namespaces-controversy/" target="_blank">namespace</a> <a href="http://michaelkimsal.com/blog/disappointed-with-php-namespace-seperator-decision/" target="_blank">decision</a>.</p>
<p>&nbsp;</p>
<h4 style="text-align: center;">» However, PHP still excels in a few areas «</h4>
<p>Having said all of that, there are a few areas where I believe PHP may still shine brighter than Python:</p>
<h4>» PHP hosting support <span style="text-decoration: line-through;">is</span> may be more prevalent than Python</h4>
<p>It&#8217;s practically unheard of to find yourself on a web host that doesn&#8217;t support PHP out of the box. However, this is becoming less and less of an issue since most Python web applications can now be deployed using tools such as FastCGI or mod_proxy (as opposed to the popular <a href="http://code.google.com/p/modwsgi/" target="_blank">mod_wsgi</a> setup, which often requires root access to configure). These days any &#8220;reputable&#8221; web host is probably going to support some sort of strategy for deploying Python web applications. Of course, this only really applies to shared hosting environments without root access. If you&#8217;ve got a VPS or dedicated server you&#8217;re fine.</p>
<h4>» PHP is arguably &#8220;more seasoned&#8221; on the web than Python</h4>
<p>The communities behind projects like Drupal and WordPress really stand out to me as examples of the maturity of PHP on the web. Although similar Python web projects have been slowly emerging (and <a href="http://plone.org/" target="_blank">Plone</a> has been around for years, if that&#8217;s your cup of tea), they don&#8217;t really compete yet in my opinion.</p>
<p>Of course, I am only talking about specific web projects here. Language wise, Python has been around longer than PHP. Web 2.0 framework wise, Python&#8217;s offerings have been around about as long as PHP&#8217;s (pretty much every language had its own answer to Ruby on Rails in 2005).</p>
<h4>» PHP <em>seems</em> easier than Python at first (and might be for simple deployments)</h4>
<p>There&#8217;s something magical about throwing together a few quick index.php/about.php/contact.php files and uploading them to the httpdocs directory of your webserver and it &#8220;just working.&#8221; A lot of simple websites have no need for acronyms like MVC, ORM, and DRY, and in those cases PHP is an excellent &#8220;server-side extension&#8221; to HTML. However, if and when you begin to scale, you&#8217;ll either find yourself switching to a full-blown framework, or throwing one together to help facilitate your growth. At that point, you&#8217;ll probably begin discovering the &#8220;dark corners&#8221; of PHP, and may find yourself wishing you had &#8220;done it right&#8221; the first time.</p>
<p>&nbsp;</p>
<h4 style="text-align: center;">» So, which is better? «</h4>
<p>Remember, the point of this post is to solidify the fact that Python can be an excellent PHP <em>replacement</em>. When it comes to programming languages, &#8220;better&#8221; is often more a case of personal preference than anything else. However, to <em>me</em> the points discussed above make Python the better choice when it comes to what <em>I</em> like in a web development language.</p>
<p>So, is Python a better web development language than PHP?<br />
Well, does Nike make a better shoe than Adidas?</p>
<p>The most honest answer is probably: &#8220;It depends.&#8221; Python definitely has some significant advantages over PHP in certain circumstances, but the same could probably be said of PHP in other circumstances (although limited to the web I imagine).</p>
<p>&nbsp;</p>
<p>I hope this post has encouraged you PHP programmers out there to take another look at Python. It may take some getting used to (Python&#8217;s way of doing things is inherently quite different than PHP&#8217;s), but you will probably find yourself thanking me later.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/11/python-as-a-php-replacement/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Dead-simple pagination wizardry with TurboGears 2</title>
		<link>http://blog.curiasolutions.com/2009/11/dead-simple-pagination-wizardry-with-turbogears-2/</link>
		<comments>http://blog.curiasolutions.com/2009/11/dead-simple-pagination-wizardry-with-turbogears-2/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 01:00:21 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[turbogears]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=556</guid>
		<description><![CDATA[I recently had to implement pagination in a TG 2 project that I&#8217;m almost finished with. Although I had previously glanced at the paginate webhelper module, I first turned to the updated TurboGears documentation to see what was &#8220;officially&#8221; written up about this subject. A lot of work has been going into the TG docs [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had to implement pagination in a TG 2 project that I&#8217;m almost finished with. Although I had previously glanced at the <a href="http://turbogears.org/2.1/docs/modules/thirdparty/webhelpers_paginate.html" target="_blank"><em>paginate</em></a> webhelper module, I first turned to the <a href="http://turbogears.org/2.1/docs/index.html" target="_blank">updated TurboGears documentation</a> to see what was &#8220;officially&#8221; written up about this subject.</p>
<p>A lot of work has been going into the TG docs in preparation for the upcoming v2.1 launch, and one little gem that was recently added was the <a href="http://turbogears.org/2.1/docs/main/Pagination/index.html" target="_blank">Pagination Quickstart</a> (thanks Lukas). While this sent me down the right path towards pagination perfection, there were a few things that came up that I felt like deserved further explanation:</p>
<ol>
<li>The <a href="http://turbogears.org/2.1/docs/modules/tgdecorators.html#tg.decorators.paginate" target="_blank">@paginate() decorator</a> is an extremely simple wrapper for the <em>paginate</em> webhelper module.</li>
<li>When paginating SQLAlchemy queries, <em>paginate</em> runs a duplicate <em>count()</em> query to figure out its current position in the data collection. While the magic of this is nice, the possible performance issues with duplicating complex SQL queries on a high-traffic website could be undesirable.</li>
<li>It&#8217;s common to have controller methods dynamically switch to a &#8220;feed template&#8221; when doing AJAX pagination. Don&#8217;t worry, <em>paginate</em> + <em>override_template</em> makes this a piece of cake!</li>
</ol>
<p>&nbsp;</p>
<blockquote><p>The @paginate() decorator makes pagination a breeze</p></blockquote>
<p>The @paginate decorator is a wrapper for the paginate module that can be added to your controller methods. Simply specify your data collection&#8217;s name as the first argument of the decorator, and pagination is &#8220;automagically&#8221; setup for you.</p>
<p>An example controller method with pagination would look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># dead-simple pagination in TurboGears 2</span>
&nbsp;
@expose<span style="color: black;">&#40;</span><span style="color: #483d8b;">'myproject.templates.posts'</span><span style="color: black;">&#41;</span>
@paginate<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;posts&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> posts<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    posts = DBSession.<span style="color: black;">query</span><span style="color: black;">&#40;</span>Posts<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>posts=posts<span style="color: black;">&#41;</span></pre></div></div>

<p>Really? That was easy!</p>
<p>The documentation on this decorator seems quite clear to me, so instead of repeating its content here I will simply give you a <a href="http://turbogears.org/2.1/docs/modules/tgdecorators.html#tg.decorators.paginate" target="_blank">link for further reading</a>.</p>
<p><span id="more-556"></span>&nbsp;</p>
<blockquote><p>SQLAlchemy pagination performance wizardry</p></blockquote>
<p>The main issue here is that the paginate module has to figure out its current position in the data collection in order to be able to spit out the right &#8220;chunk&#8221; of data (as well as to provide you with fancy stuff like &#8220;page 3 of 6&#8243;). So, by default when you give it an SQLAlchemy query object, it runs a count() query to figure this out. This results in two practically identical SQL queries (one to get the total count, and the other to return your actual collection of data). While this may not be an issue on simple queries, duplicating complex queries on a high-traffic website could be disastrous.</p>
<p>Remember, magic can be unpredictable, so before we dive into this topic there are a few things you should take into consideration:</p>
<ul>
<li>This technique is not compatible with the @paginate() decorator due to the fact that the current page arg isn&#8217;t passed into the controller method when using the decorator, so be ready to get your hands dirty with the full-blown <em>paginate</em> module.</li>
<li>The SQLAlchemy all() query method results in immediate query execution. This may have undesirable side-effects.</li>
<li>I&#8217;m sure there is a cleaner/sexier way to do this, but for the sake of time and in an effort to be verbose this is what I have come up with so far. Please leave a helpful comment below if your magic is cleaner than mine.</li>
</ul>
<p>Ok, so now that we are familiar with the problem, what is a good solution? Well, a rough hack to work around this issue is to use SQLAlchemy&#8217;s limit() and offset() query methods combined with the all() method to get SQLAlchemy to return a list instead of a query object. This puts <em>paginate</em> to work on the list instead of on the database, avoiding the extra count() query. However, as tricky as this may be, there are still problems:</p>
<ol>
<li>In order for paginate to calculate a correct current position based on the &#8220;page&#8221; it thinks it&#8217;s on, you&#8217;ve got to pad the <strong>beginning</strong> of the list you send to the paginate.Page() method with enough items to accurately reflect the &#8220;current&#8221; size of the data collection.</li>
<li>In order for paginate to know there are more records waiting to be loaded, you&#8217;ve got to pad the <strong>end</strong> of the list you send to the paginate.Page() method with at least one more item than each page&#8217;s specified item limit.</li>
</ol>
<p>This may seem confusing at first, but an example controller method should help clear things up for you:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># import the paginate webhelper</span>
<span style="color: #ff7700;font-weight:bold;">from</span> webhelpers <span style="color: #ff7700;font-weight:bold;">import</span> paginate
<span style="color: #808080; font-style: italic;"># specify the number of items you want per page</span>
items_per_page = <span style="color: #ff4500;">20</span>
&nbsp;
@expose<span style="color: black;">&#40;</span><span style="color: #483d8b;">'myproject.templates.posts'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> posts<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, page=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># specify the limit, plus 1 so the Page() method can tell if extra data is available</span>
    limit = items_per_page + <span style="color: #ff4500;">1</span>
    <span style="color: #808080; font-style: italic;"># specify the offset to start with</span>
    offset = <span style="color: black;">&#40;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>page<span style="color: black;">&#41;</span> - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> items_per_page
&nbsp;
    <span style="color: #808080; font-style: italic;"># if the offset is greater than 0, we have to pad the beginning of the list</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> offset: posts = <span style="color: black;">&#91;</span>x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>offset<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    <span style="color: #808080; font-style: italic;"># otherwise we're starting at the beginning (with an empty list)</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>: posts = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># load the DB data into the list</span>
    posts.<span style="color: black;">extend</span><span style="color: black;">&#40;</span>DBSession.<span style="color: black;">query</span><span style="color: black;">&#40;</span>Posts<span style="color: black;">&#41;</span>.<span style="color: black;">limit</span><span style="color: black;">&#40;</span>limit<span style="color: black;">&#41;</span>.<span style="color: black;">offset</span><span style="color: black;">&#40;</span>offset<span style="color: black;">&#41;</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># setup the pagination object</span>
    pagination = paginate.<span style="color: black;">Page</span><span style="color: black;">&#40;</span>posts, page, items_per_page=items_per_page<span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># either use tmpl_context or return the object in the return dict</span>
    tmpl_context.<span style="color: black;">pagination</span> = pagination
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>posts=pagination.<span style="color: black;">items</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Voilà! Now that you&#8217;re dealing with a list, pagination should work as expected without the extra &#8220;count()&#8221; query.</p>
<p>&nbsp;</p>
<blockquote><p>Use override_template() for dynamic template rendering</p></blockquote>
<p>AJAX pagination is a common practice and often provides a richer user experience than &#8220;static&#8221; pagination. Fortunately, AJAX pagination is almost as easy to setup as normal pagination, and only requires <a href="http://turbogears.org/2.1/docs/modules/thirdparty/webhelpers_paginate.html#can-i-use-ajax-ajah" target="_blank">a few extra tweaks</a> to an already simple configuration.</p>
<p>The only &#8220;tricky&#8221; thing here is if you&#8217;re accessing the same controller method for partial data as well as the full page. In such a case, you&#8217;ll need to have the controller method render two separate templates depending on if you&#8217;re asking for the &#8220;full&#8221; page, or just the listing of data. Don&#8217;t worry though, <em>paginate</em> automatically provides you with a &#8220;partial&#8221; arg that you can check against, and override_template() allows you to override whatever template you have defined in the @expose() decorator.</p>
<p>Modifying the previous example&#8217;s controller method for this type of functionality looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># add the override_template import</span>
<span style="color: #ff7700;font-weight:bold;">from</span> tg <span style="color: #ff7700;font-weight:bold;">import</span> override_template
&nbsp;
<span style="color: #808080; font-style: italic;"># add the &quot;partial&quot; arg to the controller method</span>
<span style="color: #ff7700;font-weight:bold;">def</span> posts<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, page=<span style="color: #ff4500;">1</span>, partial=<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...snip...</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> partial:
        override_template<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">posts</span>, <span style="color: #483d8b;">'mako:myproject.templates.post_feed'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>posts=pagination.<span style="color: black;">items</span><span style="color: black;">&#41;</span></pre></div></div>

<p>More information on override_template() can be found in <a href="http://turbogears.org/2.1/docs/modules/tgdecorators.html#tg.decorators.override_template" target="_blank">the docs</a>.</p>
<p>&nbsp;</p>
<p>I hope this tutorial has been helpful. I will be submitting a TG docs pull request soon, so please leave comments if you have any suggestions or feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/11/dead-simple-pagination-wizardry-with-turbogears-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Reorganizing data with list &amp; dict comprehensions</title>
		<link>http://blog.curiasolutions.com/2009/10/reorganizing-data-with-list-dict-comprehensions/</link>
		<comments>http://blog.curiasolutions.com/2009/10/reorganizing-data-with-list-dict-comprehensions/#comments</comments>
		<pubDate>Sat, 31 Oct 2009 03:58:59 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=538</guid>
		<description><![CDATA[While writing scripts, I frequently run into the issue of needing to re-arrange sets of data into a more &#8220;process friendly&#8221; format. A common issue I encounter is needing to turn a list (array) into a dictionary (associative array) or vice versa. More often than not, I find myself needing to be able to access [...]]]></description>
			<content:encoded><![CDATA[<p>While writing scripts, I frequently run into the issue of needing to re-arrange sets of data into a more &#8220;process friendly&#8221; format. A common issue I encounter is needing to turn a list (array) into a dictionary (associative array) or vice versa. More often than not, I find myself needing to be able to access list elements by a key, but since they aren&#8217;t setup in a dictionary I have to pull out a looping technique to reorganize the data for this to be possible.</p>
<p>Take the following set of data for example:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #483d8b;">'John Smith'</span>, <span style="color: #483d8b;">'admin'</span><span style="color: black;">&#93;</span>,
 <span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'Jane Doe'</span>, <span style="color: #483d8b;">'superuser'</span><span style="color: black;">&#93;</span>,
 <span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'Sam Jones'</span>, <span style="color: #483d8b;">'user'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>What we have here is a few rows of user data. In this example, the data is in a Python list (which in PHP would be an array).</p>
<p>In PHP, this would look something like (using print_r):</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #990000;">Array</span> <span style="color: #009900;">&#40;</span>
    <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">Array</span> <span style="color: #009900;">&#40;</span>
        <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">1</span>
        <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> John Smith
        <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> admin
    <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">Array</span> <span style="color: #009900;">&#40;</span>
        <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">2</span>
        <span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> Jane Doe
<span style="color: #666666; font-style: italic;"># (...etc...)</span></pre></div></div>

<p>So, what if I found myself writing some code that needed to be able to access each record by its first value, which in this case would be the user_id? <span id="more-538"></span></p>
<p>Well, in PHP the easiest way to make this happen would be a good-old-fashioned <em>foreach</em> loop:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$row</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$val</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$out</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$val</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$val</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Not very &#8220;sexy&#8221; for something I find myself having to more often than I would like, but it works nonetheless.</p>
<p>Now, here&#8217;s where the beauty of Python kicks in. Python has a built-in feature called &#8220;comprehension&#8221; which allows you to modify and/or convert sets of data quickly and easily.</p>
<p>Remember what our original data set looks like? Here&#8217;s a refresher:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> row
<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #483d8b;">'John Smith'</span>, <span style="color: #483d8b;">'admin'</span><span style="color: black;">&#93;</span>,
 <span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'Jane Doe'</span>, <span style="color: #483d8b;">'superuser'</span><span style="color: black;">&#93;</span>,
 <span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'Sam Jones'</span>, <span style="color: #483d8b;">'user'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Now, in Python all we need to do is use the dictionary comprehension:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> out = <span style="color: black;">&#123;</span>val<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>: val <span style="color: #ff7700;font-weight:bold;">for</span> val <span style="color: #ff7700;font-weight:bold;">in</span> row<span style="color: black;">&#125;</span> <span style="color: #808080; font-style: italic;"># Python 3.X</span>
<span style="color: #808080; font-style: italic;"># (or, for Python 2.X)</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> out = <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>val<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>, val<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> val <span style="color: #ff7700;font-weight:bold;">in</span> row<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Python 2.4+</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> out
<span style="color: black;">&#123;</span><span style="color: #ff4500;">1</span>: <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #483d8b;">'John Smith'</span>, <span style="color: #483d8b;">'admin'</span><span style="color: black;">&#93;</span>,
 <span style="color: #ff4500;">2</span>: <span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'Jane Doe'</span>, <span style="color: #483d8b;">'superuser'</span><span style="color: black;">&#93;</span>,
 <span style="color: #ff4500;">3</span>: <span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'Sam Jones'</span>, <span style="color: #483d8b;">'user'</span><span style="color: black;">&#93;</span><span style="color: black;">&#125;</span></pre></div></div>

<p>See how easy that was?</p>
<p>And what if I had a dictionary in the above format, and needed to turn it into the type of list I had previously? Well, I could simply use the list comprehension to re-generate this set of data as a list:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: black;">&#91;</span>val <span style="color: #ff7700;font-weight:bold;">for</span> val <span style="color: #ff7700;font-weight:bold;">in</span> out.<span style="color: black;">values</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #483d8b;">'John Smith'</span>, <span style="color: #483d8b;">'admin'</span><span style="color: black;">&#93;</span>,
 <span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'Jane Doe'</span>, <span style="color: #483d8b;">'superuser'</span><span style="color: black;">&#93;</span>,
 <span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'Sam Jones'</span>, <span style="color: #483d8b;">'user'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span></pre></div></div>

<p>This is an extremely simple comprehension example. For a deeper look, check out Wikipedia&#8217;s <a href="http://en.wikipedia.org/wiki/Python_syntax_and_semantics#Functional_programming" target="_blank">Python syntax page</a> or the <a href="http://docs.python.org/3.1/tutorial/datastructures.html" target="_blank">official Python documentation</a>. </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/10/reorganizing-data-with-list-dict-comprehensions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The great web technology shootout &#8211; Round 3: Better, Faster, and Shinier</title>
		<link>http://blog.curiasolutions.com/2009/10/the-great-web-technology-shootout-round-3-better-faster-and-shinier/</link>
		<comments>http://blog.curiasolutions.com/2009/10/the-great-web-technology-shootout-round-3-better-faster-and-shinier/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 18:42:52 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[pylons]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[turbogears]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=409</guid>
		<description><![CDATA[[A lot of the information below is out of date. Please see the new framework shootout page for the latest benchmarks.] [Note: This post is the continuation of a series. Please read Round 1 and Round 2 first if you are just now joining us.] As I briefly mentioned in Round 1, this whole thing [...]]]></description>
			<content:encoded><![CDATA[<p><strong>[A lot of the information below is out of date. Please see the new <a href="http://blog.curiasolutions.com/?p=963">framework shootout page</a> for the latest benchmarks.]</strong></p>
<p>[Note: This post is the continuation of a series. Please read <a href="http://blog.curiasolutions.com/?p=172">Round 1</a> and <a href="http://blog.curiasolutions.com/?p=278">Round 2</a> first if you are just now joining us.]</p>
<p>As I briefly mentioned in <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>, this whole thing came about as an experiment to satisfy my own curiosity. Unfortunately, I wasn&#8217;t expecting these posts to draw the amount of attention they have been getting, and several people informed me of a few &#8220;issues&#8221; with the first round. Since my initial approach to this topic was somewhat casual, I didn&#8217;t really take the time to perform each test in a &#8220;proper scientific fashion.&#8221; Although this was clearly stated in the introduction to round one, it unfortunately resulted in performance estimations that were somewhat less than accurate.</p>
<p>After input from various people much smarter than myself, I quickly went to work tweaking my test environment and building &#8220;proper&#8221; test apps. In the midst of this, a conversation about PHP accelerators prompted me to put PHP under the spotlight, which brought about <a href="http://blog.curiasolutions.com/?p=278">Round 2</a> as an interim round. This gave me a chance to demonstrate the necessity of PHP acceleration, and only continued to solidify my opinion of PHP as an inferior web development language (remember, I just said <em>my opinion</em>).</p>
<p>Which brings us to Round 3. A lot of work has gone into &#8220;doing it right&#8221; this time, so I am fairly confident that these results are a much more accurate representation of each test subject&#8217;s performance estimations. Remember, benchmark test code typically has no real-world value, so &#8220;performance estimations&#8221; are about all I can promise here. <strong>Your mileage <em>will</em> vary.</strong> As a wise person once said:</p>
<blockquote><p>&#8220;All this benchmarking is doing is proving what we already know: More code takes longer to execute.&#8221; &#8211; Ben Bangert (dev lead of Pylons)</p></blockquote>
<p><span id="more-409"></span></p>
<p>&nbsp;</p>
<p>What you should know about Round 3:</p>
<ul>
<li>The hardware/software platform is the same as in <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>.</li>
<li>Python v2.5.4 was used for all the Python tests. Ruby v1.8.6 was used for the Rails test.</li>
<li>Apache v2.2.3 was used, with <a href="http://code.google.com/p/modwsgi/" target="_blank">mod_wsgi</a> v2.5 for the Python tests and <a href="http://www.modrails.com/" target="_blank">Phusion Passenger</a> v2.2.5 for the Rails test.</li>
<li>Note that while the mod_wsgi tests in Round 1 were using &#8220;daemon mode&#8221;, the mod_wsgi tests here are using &#8220;embedded mode&#8221; which is often faster (although <a href="http://blog.dscpl.com.au/2009/03/load-spikes-and-excessive-memory-usage.html" target="_blank">not necessarily the recommended configuration)</a>.
<li>The Python component versions used here were: SQLAlchemy v0.5.6, Genshi v0.5.1, Mako v0.2.5, and Jinja 2.2.1.</li>
<li>ApacheBench was run with -n 10000 -c 10.</li>
<li>Each test was run several times to make sure that there were no anomalies, with the &#8220;optimum average&#8221; chosen as the numbers represented here.</li>
<li>In an attempt to try to make these tests more scientific, I am now including the source code for each test.</li>
</ul>
<p>&nbsp;</p>
<blockquote><h4>Plain WSGI – <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/wsgi_test_src.zip">wsgi_test_src.zip</a></h4>
</blockquote>
<p>Let&#8217;s start with a basic &#8220;hello world&#8221; WSGI test to set the baseline:</p>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">WSGIServer</span><span style="color: #66cc66;">/</span><span style="color: #cc66cc;">0.1</span>
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">1532.76</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Apache<span style="color: #66cc66;">/</span>2<span style="color: #66cc66;">.</span>2<span style="color: #66cc66;">.</span>3 <span style="color: #66cc66;">&#40;</span>mod_wsgi<span style="color: #66cc66;">&#41;</span>
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">5549.73</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, mod_wsgi allows Apache to put some serious muscle into Python&#8217;s WSGI. It&#8217;s no wonder that mod_wsgi is quickly becoming the de-facto standard for Apache Python deployment.</p>
<p>&nbsp;</p>
<blockquote><h4>TurboGears v2.0.3 – <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/tg2_test_src.zip">tg2_test_src.zip</a></h4>
</blockquote>
<p>As I mentioned in Round 1, <a href="http://www.turbogears.org/" target="_blank">TurboGears</a> has quickly become my web framework of choice. Building a &#8220;best-of-breed&#8221; component stack on top of Pylons <a href="http://percious.com/blog/?p=31" target="_blank">may not be easy</a>, but <a href="http://percious.com/blog/?p=32" target="_blank">when it works</a> I believe it pays off immensely (e.g. Ubuntu).</p>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">935.13</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Genshi template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>genshi_hello<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">923</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">601.07</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Mako template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>mako_hello<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">932</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">723.18</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Jinja2 template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>jinja_hello<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">937</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">764.35</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> tests<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>raw_sql<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">1270</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">569.71</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>genshi_sql<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2409</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">388.96</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>mako_sql<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2418</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">515.07</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>jinja_sql<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2472</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">535.06</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>&nbsp;</p>
<blockquote><h4>TurboGears v2.1a1 – <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/tg21_test_src.zip">tg21_test_src.zip</a></h4>
</blockquote>
<p>The TurboGears community is alive and well, and just before finishing this post the release of v2.1 Alpha 1 was announced. Significant improvements were made to TG&#8217;s object dispatch, so I was excited to see what the new numbers would look like.</p>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">11</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">1118.92</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Genshi template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>genshi_hello<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">923</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">713.97</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Mako template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>mako_hello<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">932</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">812.64</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Jinja2 template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>jinja_hello<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">937</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">1000.98</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> tests<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>raw_sql<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">1270</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">673.04</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>genshi_sql<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2409</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">433.45</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>mako_sql<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2418</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">601.89</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>jinja_sql<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2472</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">630.66</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, the future of TurboGears looks very bright, and I only expect these numbers to get better as the final 2.1 release approaches (expected in Q1 2010).</p>
<p>&nbsp;</p>
<blockquote><h4>Pylons v0.9.7 – <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/pylons_test_src.zip">pylons_test_src.zip</a></h4>
</blockquote>
<p><a href="http://www.pylonshq.com/" target="_blank">Pylons</a> is the foundation which TurboGears is built upon, and for those who don&#8217;t need all &#8220;the extras&#8221; it is an excellent choice.</p>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">2593.47</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Mako template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span>hello
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">932</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">1737.03</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> tests<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span>raw_sql
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">1270</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">964.07</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span>hellodb
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2418</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">831.26</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>&nbsp;</p>
<blockquote><h4>Django v1.1 – <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/django_test_src.zip">django_test_src.zip</a></h4>
</blockquote>
<p>While <a href="http://www.djangoproject.com/" target="_blank">Django</a> is probably Python&#8217;s most popular web framework, I have never really clicked with it. Its way of doing things is significantly different than TG/Pylons, but if you don&#8217;t mind its &#8220;<a href="http://docs.djangoproject.com/en/dev/faq/general/#django-appears-to-be-a-mvc-framework-but-you-call-the-controller-the-view-and-the-view-the-template-how-come-you-don-t-use-the-standard-names" target="_blank">MTV</a>&#8221; architectural pattern and can survive without SQLAlchemy (although there are hacks), it is a very capable framework.</p>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">3376.48</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Django template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">936</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">1781.43</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellodb
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2476</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">972.11</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>&nbsp;</p>
<blockquote><h4>Bottle 0.5.8 – <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/bottle_test_src.zip">bottle_test_src.zip</a></h4>
</blockquote>
<p><a href="http://bottle.paws.de/" target="_blank">Bottle</a> caught my attention a few months ago while surveying the WSGI landscape for an alternative to PHP when building websites that only require a few pieces of dynamic functionality. As a &#8220;micro-framework&#8221;, it does an excellent job at bridging the gap between &#8220;pure WSGI&#8221; and its &#8220;feature-rich&#8221; big brothers.</p>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">5545.96</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Mako template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">923</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">3588.04</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span>SQLAlchemy<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellodb
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2413</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">1479.54</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, there was practically no difference in speed between Bottle and pure WSGI in a basic &#8220;hello world&#8221; test. Even with the addition of Mako and SQLAlchemy, Bottle performed significantly faster than a bare Pylons or Django setup.</p>
<p>(Note: Mako template inheritance was not used in the Bottle Mako test.)</p>
<p>&nbsp;</p>
<blockquote><h4>Ruby on Rails v2.3.3 – <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/rails_test_src.zip">rails_test_src.zip</a></h4>
</blockquote>
<p>What web technology shootout would be complete without <a href="http://www.rubyonrails.org/" target="_blank">Rails</a>? Although I am not a Rails fan (mostly because I can&#8217;t stand Ruby), I believe that in many ways we owe much of the popularity and success of the web framework movement to Rails.</p>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span>hello
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">1048.18</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Rails template test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span>hellos
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">937</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">949.54</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
&nbsp;
Database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span>hellodb
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2482</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">734.18</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>(Note: I think my version of Ruby was using a newer version of the SQLite3 library than my version of Python. This may or may not have given Rails an advantage on the database query test.)</p>
<p>&nbsp;</p>
<p>For those of you who like charts, here&#8217;s a comparison of the &#8220;return hello world&#8221; test results for each framework:</p>
<div id="attachment_531" class="wp-caption aligncenter" style="width: 566px"><a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/hello_world_test.png"><img src="http://blog.curiasolutions.com/wp-content/uploads/2009/10/hello_world_test.png" alt="The return hello world test chart" title="Hello World Test" width="556" height="352" class="size-full wp-image-531" /></a><p class="wp-caption-text">The return hello world test chart</p></div>
<p>And here&#8217;s a comparison of the template test:</p>
<div id="attachment_532" class="wp-caption aligncenter" style="width: 566px"><a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/template_test.png"><img src="http://blog.curiasolutions.com/wp-content/uploads/2009/10/template_test.png" alt="The template test chart" title="Template Test" width="556" height="263" class="size-full wp-image-532" /></a><p class="wp-caption-text">The template test chart</p></div>
<p>Finally, here&#8217;s the template test with the database query added:</p>
<div id="attachment_530" class="wp-caption aligncenter" style="width: 566px"><a href="http://blog.curiasolutions.com/wp-content/uploads/2009/10/database_test.png"><img src="http://blog.curiasolutions.com/wp-content/uploads/2009/10/database_test.png" alt="Template test with database query" title="Database Query" width="556" height="264" class="size-full wp-image-530" /></a><p class="wp-caption-text">Template test with database query</p></div>
<p>&nbsp;</p>
<h4>Closing thoughts</h4>
<ul>
<li>Gone are the days of Rails as &#8220;the one framework to rule them all.&#8221; C&#8217;mon guys, it&#8217;s not 2005 anymore.</li>
<li>Python has gotten a lot of flak from other language camps for its abundance of web frameworks. While some Pythonists have been embarrassed by this, I only see it as proof of Python&#8217;s success as a language. My retort would be: &#8220;If it was as easy to write a web framework in your language as it is in Python, you&#8217;d have the same problem!&#8221;</li>
</ul>
<p>&nbsp;</p>
<h5>Looking for updated results? Check out <a href="http://blog.curiasolutions.com/?p=915">Round 4</a>&#8230;</h5>
<p>(Note: Please don&#8217;t leave benchmarking requests as comments. If you&#8217;d like me to take a look at your favorite framework, direct message me on twitter. Thanks!)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/10/the-great-web-technology-shootout-round-3-better-faster-and-shinier/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>The great web technology shootout &#8211; Round 2: PHP deserves a helping hand</title>
		<link>http://blog.curiasolutions.com/2009/09/the-great-web-technology-shootout-round-2-php-deserves-a-helping-hand/</link>
		<comments>http://blog.curiasolutions.com/2009/09/the-great-web-technology-shootout-round-2-php-deserves-a-helping-hand/#comments</comments>
		<pubDate>Tue, 22 Sep 2009 06:53:41 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=278</guid>
		<description><![CDATA[[A lot of the information below is out of date. Please see the new framework shootout page for the latest benchmarks.] [This post is the continuation of a series. Please read Round 1 first if you are just now joining us.] In Round 1, PHP was looking like quite the tortoise of the group. However, [...]]]></description>
			<content:encoded><![CDATA[<p><strong>[A lot of the information below is out of date. Please see the new <a href="http://blog.curiasolutions.com/?p=963">framework shootout page</a> for the latest benchmarks.]</strong></p>
<p>[This post is the continuation of a series. Please read <a href="http://blog.curiasolutions.com/?p=172">Round 1</a> first if you are just now joining us.]</p>
<p>In <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>, PHP was looking like quite the tortoise of the group. However, if you&#8217;re familiar with some of the core differences between Python &amp; PHP, you&#8217;ll know that Python has been &#8220;cheating&#8221; slightly.</p>
<p>Let me explain: By default, Python compiles each script into bytecode on its first execution, allowing this bottleneck to be skipped on subsequent runs. PHP, however does not perform this type of optimization by default (in the 5.x line at least), so the PHP interpreter must re-compile each file every time it is run. As you can imagine, this can give PHP (without an accelerator) a huge disadvantage when compared to languages such as Python.</p>
<p><strong>With this in mind, I have decided to take Round 2 to focus solely PHP.</strong> This will hopefully provide a clear picture of the benefits of PHP bytecode caching (at least when it comes to page-views — the memory benefits are a whole other story), and give you an idea of PHP&#8217;s performance with the help of an accelerator.</p>
<p>There are <a href="http://en.wikipedia.org/wiki/List_of_PHP_accelerators" target="_blank">many PHP accelerators available</a>, but I have chosen <a href="http://php.net/apc" target="_blank">APC</a> for use here (mostly due to its inclusion in the upcoming PHP 6 core).<span id="more-278"></span></p>
<h5>What you should know about Round 2:</h5>
<ol>
<li>The hardware/software platform is the same as in <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>.</li>
<li>PHP has been upgraded to v5.2.9.</li>
<li>The APC tests are using APC v3.0.19.</li>
<li>ApacheBench was run with -n # -c 10, with -n usually being 5000 or 10000, depending on the test subject&#8217;s speed.</li>
<li>Each test was run several times to make sure that there were no anomalies, with the &#8220;optimum average&#8221; chosen as the numbers represented here.</li>
<li>In an attempt to try to make these tests more scientific, I am now including the source code for each test (minus the CMS tests, which were performed on a standard install).</li>
</ol>
<p>My apc.ini settings:</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;"><span style="color: #000099;">extension</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> apc.so</span>
apc.enabled <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> 1</span>
apc.shm_size <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> 96</span>
apc.include_once_override <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> 1</span>
apc.mmap_file_mask <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> /tmp/apc.XXXXXX</span></pre></div></div>

<blockquote>
<h4>Raw PHP &#8211; <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/09/php_test_src.zip">php_test_src.zip</a></h4>
</blockquote>
<p>To investigate the speed of &#8220;raw PHP&#8221;, I created a couple of minimal PHP scripts that printed out a simple &#8220;hello world&#8221;, and read a few lines of text from a database. Take a look at the test source code for reference.</p>
<h5>APC Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">.</span>php
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">4199.43</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello_db<span style="color: #66cc66;">.</span>php
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2524</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">2797.54</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">.</span>php
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">6618.42</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello_db<span style="color: #66cc66;">.</span>php
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2524</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">3713.99</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Right out of the gate, we can see that APC gives PHP a significant boost.</p>
<p>Of course, a script that simply does a &#8220;echo &#8216;hello world&#8217;&#8221; isn&#8217;t really practical, so let&#8217;s take a look at a couple of popular PHP frameworks to see what a full stack looks like.</p>
<blockquote>
<h4>CakePHP v1.2.5 &#8211; <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/09/cakephp_test_src.zip">cakephp_test_src.zip</a></h4>
</blockquote>
<p>CakePHP was the slowest test subject by a large margin in <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>, but if you take a look at the caching section of its core configuration file you can see that the developers have written it with acceleration in mind. It includes special configuration directives for not just APC, but also <a href="http://xcache.lighttpd.net/" target="_blank">Xcache</a> and <a href="http://www.danga.com/memcached/" target="_blank">Memcache</a>.</p>
<p>Still though, without acceleration CakePHP is a sad story indeed:</p>
<h5>APC Disabled &#8211; File Caching Engine (default)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">13</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">45.25</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The template hello world test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>hello
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">931</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">39.90</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the ORM<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>hello_db
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2469</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">38.80</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>However, with the help of APC things finally begin to look reasonable:</p>
<h5>APC Enabled &#8211; APC Caching Engine (in core.php)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">13</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">140.98</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The template hello world test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>hello
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">931</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">120.04</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the ORM<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>hello_db
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2469</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">117.56</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, APC increases CakePHP&#8217;s speed about threefold in these examples. These results may or may not be acceptable to you (remember that we are running these tests with a concurrency of 10), but I felt much better about CakePHP after pairing it with APC.</p>
<blockquote>
<h4>Kohana v3.0 &#8211; <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/09/kohana3_test_src.zip">kohana3_test_src.zip</a></h4>
</blockquote>
<p>Kohana (a divergent of CodeIgnitor) is a much more lightweight PHP framework than CakePHP, but still gives you a pretty full featureset. Since v3.0 was released shortly after <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>, I decided to use the new version for the tests here in Round 2.</p>
<p>It should be noted that although file caching is enabled in a default CakePHP install, Kohana&#8217;s caching is disabled by default. I have included a couple of tests with caching disabled here to exhibit the performance of a default Kohana install.</p>
<h5>APC Disabled &#8211; Caching Disabled (default)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">86.73</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Disabled &#8211; Caching Enabled (bootstrap.php)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">180.50</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The template hello world test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">930</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">162.27</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the Database module<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellodb<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2525</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">113.92</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the ORM module<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>helloorm<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2525</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">99.73</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, even without APC Kohana is quite a bit faster than CakePHP.</p>
<h5>APC Enabled &#8211; Caching Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">125.93</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled &#8211; Caching Enabled (bootstrap.php)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">280.67</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The template hello world test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">930</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">253.50</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the Database module<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellodb<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2525</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">173.28</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the ORM module<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>helloorm<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2525</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">153.90</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Although not a threefold gain as with CakePHP, Kohana with APC+caching definitely makes a good attempt at shortening the gap seen in <a href="http://blog.curiasolutions.com/?p=172">Round 1</a> between the PHP frameworks and the offerings from other languages. Of course, if raw speed is what you&#8217;re looking for, there are <a href="http://www.doophp.com/benchmark" target="_blank">faster PHP frameworks available</a> (note that the benchmarks on that page were run on a completely different setup and should not be compared with any of the numbers here).</p>
<p><strong>Next, let&#8217;s take a look at how APC enhances the performance of a few of PHP&#8217;s heavyweights.</strong></p>
<blockquote>
<h4>WordPress v2.8.4 (default install)</h4>
</blockquote>
<p>Although I&#8217;ve heard that WordPress has a built-in caching setting, a quick glance at wp-settings.php did not reveal anything. So, there are simply two WordPress tests—with APC, and without:</p>
<h5>APC Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5519</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">24.80</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5519</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">74.00</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<blockquote>
<h4>Joomla v1.5.14 (default install, without sample data)</h4>
</blockquote>
<p>The results of these tests were quite disappointing to me, and made me wonder if I was doing something wrong. Sadly, it looks as though Joomla is quite the slow one of the bunch.</p>
<h5>APC Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Joomla Caching Disabled <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">DEFAULT</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">4006</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">27.90</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Joomla Caching Enabled <span style="color: #66cc66;">&#40;</span>File<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">4006</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">31.46</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Joomla Caching Disabled<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">4006</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">41.27</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Joomla Caching Enabled <span style="color: #66cc66;">&#40;</span>APC<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">4006</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">45.01</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<blockquote>
<h4>Drupal v6.14 (default install, clean URLs disabled)</h4>
</blockquote>
<p>Drupal has several caching settings, so I decided to see what each one would look like and how much of a difference &#8220;aggressive&#8221; caching made.</p>
<h5>APC Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Drupal Caching Disabled <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">DEFAULT</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">36.72</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #ff0000;">&quot;Normal&quot;</span> Drupal Caching<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">289.69</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #ff0000;">&quot;Aggressive&quot;</span> Drupal Caching<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">335.68</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Drupal Caching Disabled<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">83.93</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #ff0000;">&quot;Normal&quot;</span> Drupal Caching<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">498.37</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #ff0000;">&quot;Aggressive&quot;</span> Drupal Caching<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">564.48</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, Drupal&#8217;s caching (especially when combined with APC) changes things drastically. These results seem to indicate that Drupal&#8217;s caching does a great job of allowing the CMS to get out of the way.</p>
<h4>Closing thoughts</h4>
<ul>
<li>The benefits of a PHP accelerator are really too good to pass up. Even without written-in caching, an accelerator can give your code a significant boost.</li>
<li>While these tests have only really explored the impact on website page-load times, a PHP accelerator typically also cuts down on the amount of memory used by your PHP scripts.</li>
<li>PHP 6 has promised to fix a lot of things, including the lack of built-in bytecode caching. It will be interesting to revisit these tests in a few years (?) to see how much optimization the new version brings to the table.</li>
</ul>
<h5>Can&#8217;t get enough of this madness? Just wait until you read <a href="http://blog.curiasolutions.com/?p=409">Round 3</a>!</h5>
<p>(Note: Please don&#8217;t leave benchmarking requests as comments. If you&#8217;d like me to take a look at your favorite framework, direct message me on twitter. Thanks!)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/09/the-great-web-technology-shootout-round-2-php-deserves-a-helping-hand/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
