Browse Source

Improvements for the multi-query tests.

These changes will work for both django and django_stripped

I've explained the changes line by line so that anyone can run them many ways.  I tested out certain portions (like declaring dictionaries on the fly with string literals instead of identifiers pointing to the literals) to make sure this is somewhat nice.  Using partials and eliminating de-references (dot-notation) removes a lot of call-stack overhead, not to mention making downstream code really succinct for what it's doing.  If you don't believe me, too bad; here's proof:
# with random partial
In [19]: %timeit [rp() for x in xrange(1000)]
10000 loops, best of 3: 97.2 us per loop

# with unnecessary dereference
In [20]: %timeit [random.randint(1000) for x in xrange(1000)]
10000 loops, best of 3: 146 us per loop

In [21]: ri = random.randint

# without frivolous dereference
In [22]: %timeit [ri(1000) for x in xrange(1000)]
10000 loops, best of 3: 108 us per lo
Brian Knapp 12 years ago
parent
commit
7d8c7fcbc5
1 changed files with 27 additions and 6 deletions
  1. 27 6
      django/hello/world/views.py

+ 27 - 6
django/hello/world/views.py

@@ -8,6 +8,8 @@ from django.shortcuts import render
 import ujson
 import ujson
 import random
 import random
 from operator import attrgetter
 from operator import attrgetter
+import numpy.random as nprnd
+from functools import partial
 
 
 def json(request):
 def json(request):
   response = {
   response = {
@@ -17,13 +19,32 @@ def json(request):
 
 
 def db(request):
 def db(request):
   queries = int(request.GET.get('queries', 1))
   queries = int(request.GET.get('queries', 1))
-  worlds  = []
-
-  for i in range(queries):
+  # worlds = []
+  # it's not required to explicitly loop instead of using list comprehension
+  #for i in range(queries):
     # get a random row, we know the ids are between 1 and 10000
     # get a random row, we know the ids are between 1 and 10000
-    worlds.append(World.objects.get(id=random.randint(1, 10000)))
-
-  return HttpResponse(serializers.serialize("json", worlds), mimetype="application/json")
+    #worlds.append(World.objects.get(id=random.randint(1, 10000)))
+  # instead we can do:
+  #worlds = [World.objects.get(id=random.randint(1, 10000)) for i in range(queries)]
+  
+  # fun fact:  every dot-notation lookup calls some python magic under the hood.  Like every other code,
+  # one can eliminate dereferences by storing the end dereferenced thing in an identifier
+  g = World.objects.get
+  #r = random.randint
+  # but wait! there's more!
+  #http://stackoverflow.com/questions/4172131/create-random-list-of-integers-in-python
+  #r = nprnd.randint
+  # but wait!  there's more!  if we're calling a function over and over with the same parameters, 
+  # we can use even more function magic.
+  rp = partial(nprnd.randint, 10000)
+  # now we're ready to write our awesome query iterator thingy
+  # first of all, we know the id's correspond to the random number we're picking, so we can create
+  # dictionaries on the fly instead of serializing later
+  # by creating dicts, we don't need to user the model serializer, which is probably slow and only appropriate
+  # for complicated serializations of joins and crazy query sets etc
+  # test xrange vs range if the query number is gigantic
+  worlds = ujson.dumps([{'id' : r, 'randomNumber' : g(id=r).randomnumber} for r in [rp() for q in xrange(queries)]])  
+  return HttpResponse(worlds, mimetype="application/json")
 
 
 def fortunes(request):
 def fortunes(request):
   fortunes = list(Fortune.objects.all())
   fortunes = list(Fortune.objects.all())