Tornado crashed with assert error
Question: According to official doc <http://tornado.readthedocs.org/en/latest/gen.html>,
I'm using async feature of tornado like this:

    
    
    @tornado.web.asynchronous
    @tornado.gen.coroutine
    def get(self):
        ...
        response = yield calendar.events()
        self.write(json.dumps(response, default=json_util.default))
        self.finish()
    

`calendar.events()` is database operation, it crashed with below assert error,
is there anything wrong?

    
    
    HTTPServerRequest(protocol='http', host='xxxx:9999', method='GET', uri='/event_list?calendar_guid=6', version='HTTP/1.1', remote_ip='xxxx', headers={'Host': 'xxxx:9999', 'User-Agent': 'Mozilla/5.0 (apple-x86_64-darwin14.4.0) Siege/3.1.0', 'Connection': 'close', 'Accept': '*/*', 'Accept-Encoding': 'gzip'})
    Traceback (most recent call last):
      File "/usr/local/lib/python2.7/dist-packages/tornado/web.py", line 1369, in _stack_context_handle_exception
        raise_exc_info((type, value, traceback))
      File "/usr/local/lib/python2.7/dist-packages/tornado/web.py", line 1572, in wrapper
        result = method(self, *args, **kwargs)
      File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 242, in wrapper
        Runner(result, future, yielded)
      File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 817, in __init__
        if self.handle_yield(first_yielded):
      File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 956, in handle_yield
        self.future = convert_yielded(yielded)
      File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 1022, in convert_yielded
        return multi_future(yielded)
      File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 643, in multi_future
        assert all(is_future(i) for i in children)
    AssertionError
    


Answer: To be used with the `yield` statement in a Tornado coroutine, a method must be
specifically written for this purpose. Looks like the `calendar.events` method
you call does not return a Tornado `Future` object, so I infer it's not
designed for use as a non-blocking method within a Tornado coroutine.

You can call it without the `yield` keyword, but you'll have to accept that
you're blocking the event loop while `events` executes. Alternatively, use a
ThreadPoolExecutor. Tornado's maintainer Ben Darnell has a nice example of
this here:

<https://groups.google.com/d/msg/python-tornado/35BiBKdSCNw/zx561l-sABIJ>

If `calendar` is a MySQLdb object, try:

    
    
    from concurrent.futures import ThreadPoolExecutor
    from tornado.process import cpu_count
    
    # global threadpool
    pool = ThreadPoolExecutor(cpu_count())
    
    class Handler(RequestHandler):
        @tornado.gen.coroutine
        def get(self):
            response = yield pool.submit(calendar.events)
            self.write(json.dumps(response, default=json_util.default))
    

Final notes: with `gen.coroutine`, the `asynchronous` decorator is not needed,
nor is `self.finish`.

