"""A web app to test multi-threading."""

import sys
import threading
import time

from google.appengine.ext import webapp

from ndb import tasklets, context


@tasklets.tasklet
def fibonacci(n):
  """A recursive Fibonacci to exercise task switching."""
  if n <= 1:
    raise tasklets.Return(n)
  a = yield fibonacci(n-1)
  b = yield fibonacci(n-2)
  raise tasklets.Return(a + b)


class FiboHandler(webapp.RequestHandler):

  @context.toplevel
  def get(self):
    num = 10
    try:
      num = int(self.request.get('num'))
    except Exception:
      pass
    t0 = time.time()
    ans = yield fibonacci(num)
    t1 = time.time()
    self.response.out.write('fibonacci(%d) == %d # computed in %.3f\n' %
                            (num, ans, t1-t0))


urls = [
  ('/fibo', FiboHandler),
  ]

app = webapp.WSGIApplication(urls)

@@ -35,16 +35,31 @@
 ng.%22%22%22%0A%0A
+import logging%0A
 import s
@@ -91,16 +91,58 @@
 t time%0A%0A
+from google.appengine.api import memcache%0A
 from goo
@@ -194,25 +194,32 @@
 ort 
-tasklets, context
+context, model, tasklets
 %0A%0A%0A@
@@ -356,16 +356,19 @@
 n(n)%0A  a
+, b
  = yield
@@ -386,266 +386,1412 @@
 n-1)
-%0A  b = yield fibonacci(n-2)%0A  raise tasklets.Return(a + b)%0A%0A%0Aclass FiboHandler(webapp.RequestHandler):%0A%0A  @context.toplevel%0A  def get(self):%0A    num = 10%0A    try:%0A      num = int(self.request.get('num'))%0A    except Exception:%0A      pass%0A    t0 = time.time()%0A
+,fibonacci(n-2)%0A  raise tasklets.Return(a + b)%0A%0A%0Aclass FibonacciMemo(model.Model):%0A  arg = model.IntegerProperty()%0A  value = model.IntegerProperty()%0A%0A%0A@tasklets.tasklet%0Adef memoizing_fibonacci(n):%0A  %22%22%22A memoizing recursive Fibonacci to exercise RPCs.%22%22%22%0A  if n %3C= 1:%0A    raise tasklets.Return(n)%0A  key = model.Key(FibonacciMemo, str(n))%0A  memo = yield key.get_async(ndb_should_cache=False)%0A  if memo is not None:%0A    assert memo.arg == n%0A    logging.info('memo hit: %25d -%3E %25d', n, memo.value)%0A    raise tasklets.Return(memo.value)%0A  logging.info('memo fail: %25d', n)%0A  a = yield memoizing_fibonacci(n-1)%0A  b = yield memoizing_fibonacci(n-2)%0A  ans = a + b%0A  memo = FibonacciMemo(key=key, arg=n, value=ans)%0A  logging.info('memo write: %25d -%3E %25d', n, memo.value)%0A  yield memo.put_async(ndb_should_cache=False)%0A  raise tasklets.Return(ans)%0A%0A%0ATRUE_VALUES = frozenset(%5B'1', 'on', 't', 'true', 'y', 'yes'%5D)%0A%0A%0Aclass FiboHandler(webapp.RequestHandler):%0A%0A  @context.toplevel%0A  def get(self):%0A    num = 10%0A    try:%0A      num = int(self.request.get('num'))%0A    except Exception:%0A      pass%0A    if self.request.get('reset') in TRUE_VALUES:%0A      logging.info('flush')%0A      yield model.delete_multi_async(x.key for x in FibonacciMemo.query())%0A    t0 = time.time()%0A    if self.request.get('memo') in TRUE_VALUES:%0A      memo_type = 'memoizing '%0A      ans = yield memoizing_fibonacci(num)%0A    else:%0A      memo_type = ''%0A  
     
@@ -1867,16 +1867,18 @@
 .write('
+%25s
 fibonacc
@@ -1942,16 +1942,27 @@
        (
+memo_type, 
 num, ans

Add memoizing variant.