(“abstract”?) way • Explain when we need async web servers • Why is async hard? • What is Tornado and how does it work? • Using Tornado with PyMongo, and with AsyncMongo • Motor, my experimental driver
app • Short-‐polling is CPU-‐bound: tradeoff between latency and load • Long-‐polling is memory bound • “C10K problem”: kegel.com/c10k.html • Tornado was invented for this
of Stackless Python, packaged as a module for standard Python • Greenlet stacks are stored on heap, copied to / from OS stack on resume / pause • CooperaVve • Memory-‐efficient
= handler # _impl is epoll or kqueue or ... self._impl.register(fd, events) def start(self): while True: event_pairs = self._impl.poll() for fd, events in event_pairs: self._handlers[fd](fd, events)
• Gevent works great with pymongo – monkey.patch_socket(); monkey.patch_thread() • Tornado works so-‐so – asyncmongo • No replica sets, only first batch, no SON manipulators, no document classes, … – pymongo • OK if all your queries are fast • Use extra Tornado processes
be official in a few months • Uses Tornado IOLoop and IOStream • Presents standard Tornado callback API • Stores state internally with greenlets • github.com/ajdavis/mongo-‐python-‐driver/tree/tornado_async
MotorConnection() @tornado.web.asynchronous @gen.engine def post(self): yield gen.Task(self.c.open) self.c.db.collection.insert( {‘foo’:’bar’}, callback=(yield gen.Callback(’insert'))) while cursor.alive: for i in (yield gen.Wait(’insert')): self.write(json.dumps(i)) self.write(']')
Makes socket non-blocking self.stream = tornado.iostream.IOStream(socket) def sendall(self, data): child_gr = greenlet.getcurrent() # This is run by IOLoop on the main greenlet # when data has been sent; # switch back to child to continue processing def sendall_callback(): child_gr.switch() self.stream.write(data, callback=sendall_callback) 4 5 7