There have a been a couple of posts recently, the first an excellent one by Eric Florenzano about creating a pure wsgi application as a high throughput way of persisting the number of plays various songs have had. The second was by Christian (Doswki?) a comparitive version using CherrPy indicating how more readable a framework level solution was (albeit over 100% slower).
I was interested how our rest oriented toolkit would look and also how it would perform doing the same thing. My first step was to use paster to create a template project
paster create --template=restish
I named the project ‘songs’ and then edited the songs/resource/root.py as follows
from restish import http, resource
from collections import defaultdict
global counts
counts = defaultdict(int)
class Root(resource.Resource):
@resource.GET(accept='text')
def text(self, request):
res = ','.join(['%s=%s' % (k, v) for k, v in counts.iteritems()])
return http.ok([], res)
@resource.DELETE(accept='text')
def delete(self, request):
return http.ok([], 'OK')
@resource.child('song/{id}')
def song(self, request, segments, id):
return Song(id)
class Song(resource.Resource):
def __init__(self, id):
self.id = id
@resource.GET(accept='text')
def text(self, request):
return http.ok([], str(counts[id]))
@resource.POST(accept='text')
def post(self, request):
counts[id] += 1
return http.ok([], str(counts[id]))
Restish tries not to perform much ‘magic’ and so you can construct your resources any way you like, in this case I’ve added decorators to mark up the methods that will process the http methods. I’ve made them all text/plain (using ‘text’ for shot).
The Root method is registered at the top of the application and I have a single child decorated method that passes control over to the Song resource.
The source code isn’t as readable as the CherryPy version nor is at as fast as the WSGI only version (On my Thinkpad T61 I got 750 req/sec for restish, 520 req/sec for CherryPy and 1100 req/sec for WSGI) . I’d like to think that it provides a well balanced middle ground, close to ‘meta’ but still readable and with a lot of restish (sic) flexibility.
I ran the test with spawning using the following
spawn --factory=spawning.paste_factory.config_factory development.ini -t 0
As a response to the original post, I really like the use of HTTP as a coupling protocol. I should add as an aside that I had to switch off a lot of instinctive reflexes in order to write that global line. (Sorry about the blog post title)


4 comments:
Good post Tim. restish looks similar to CherryPy using the MethodDispatcher.
One thing - I don't think your global line is doing anything. global is just used inside of callables roughly to declare that assignments to the variable in question should happen in the global scope.
I don't think the global statement was needed in Eric's original either. dict.clear() does the job of emptying a dict quite nicely.
Christian Wyglendowski
ps - never adopt a nickname that is a substring of your last name; it is infinitely confusing to the interwebs ;-)
dowski.com: Great point! I never thought to use dict.clear(), would have saved my eyes (and, frankly, my soul) from using global
timparkin: Fantastic post, thanks for writing it! I think that nobody would disagree that your solution is a *lot* more readable than mine. However, I still think that it would be very tough to beat the pure wsgi version that I wrote in terms of raw performance. It's quite cool to see the tradeoff so visually, though.
dowski.com: Thanks Christian.. Matt had told me about the globals, I'm sooo glad it wasn't needed :-)
I should also add that in later tests, CherryPy was about 600 reqs/sec so not quite as bad as you thought..
Eric Florenzano: I was very impressed at the rate of throughput pure wsgi gives you .. I think two big contributing bottlenecks are webob.Request and the child decorators. I replaced accept and child decorators with simple if/thens and let the resource work out the child to call itself.. The number of reqs/sec went up from 750 to 880 ..
As an interesting aside, I also tried Werzkeug which managed over 900 reqs/sec, mostly mamaged by a lightweight Request object I think.
Im waiting for the http://python-smisk.org/ variant :)
Post a Comment