asyncmongoのトルネードサーバーでのインラインコールバック

数週間前、トルネード開発者は、インラインコールバック(TwistedのinlineCallbacks、Node.jsのSeq、RubyのFibersの類似物)を作成するためのネイティブモジュールを追加しました。

以下は、使用例とasyncmongo(mongoDBの非同期ドライバー)に関連する例です。



比較のために、カルベックの古典的な例を示します

class AsyncHandler(RequestHandler): @asynchronous def get(self): http_client = AsyncHTTPClient() http_client.fetch("http://example.com", callback=self.on_fetch) def on_fetch(self, response): do_something_with_response(response) self.render("template.html")
      
      





そして、新しいモジュール「tornado.gen」で

  class GenAsyncHandler(RequestHandler): @asynchronous @gen.engine def get(self): http_client = AsyncHTTPClient() response = yield gen.Task(http_client.fetch, "http://example.com") do_something_with_response(response) self.render("template.html")
      
      





Twistedと同様に、呼び出しはジェネレーターを介して行われます。



メソッドの配列を呼び出すこともできます;指定されたすべてのメソッドが解決されると制御が戻ります

  def get(self): http_client = AsyncHTTPClient() response1, response2 = yield [gen.Task(http_client.fetch, url1), gen.Task(http_client.fetch, url2)]
      
      







また、異なるタイミングで起動されるすべての必要なメソッドの完了を待機する便利なメカニズム(コールバックメソッドと待機メソッド)も追加されました。

  class GenAsyncHandler2(RequestHandler): @asynchronous @gen.engine def get(self): http_client = AsyncHTTPClient() http_client.fetch("http://example.com", callback=(yield gen.Callback("key")) response = yield gen.Wait("key") do_something_with_response(response) self.render("template.html")
      
      





上記の例はすべてtornado.genモジュールから取られました



asyncmongoで使用する方法の例

 class MainHandler(tornado.web.RequestHandler): @property def db(self): if not hasattr(self, '_db'): self._db = asyncmongo.Client(pool_id='mydb', host='127.0.0.1', \ port=27017, maxcached=10, maxconnections=50, dbname='test') return self._db @web.asynchronous @gen.engine def get(self): r, error = yield gen.Task(self.db.user.save, { 'login':'tester' }) r, error = yield gen.Task(self.db.user.find_one, {}) self.write(str(r[0])) self.finish()
      
      





ここでは、結果を取得するためにsaveメソッドとfind_oneメソッドが順番に呼び出されます。



次の例では、松葉杖のラッパーを作成しました。これにより、mongodbの使用は古典的なもののようになりました(db.user.save({'login': 'tester'})、db.user.find_one({}))

 class MainHandler(tornado.web.RequestHandler): @property def db(self): if not hasattr(self, '_db'): self._db = tornadomongo.mongo_client(pool_id='mydb', host='127.0.0.1', port=27017, maxcached=10, maxconnections=50, dbname='test') return self._db @web.asynchronous @gen.engine def get(self): # save r = yield self.db.user.save({ 'login':'tester' }) # find try: r = yield self.db.user.find_one({}) self.write(str(r)) except tornadomongo.MongoError as e: self.write('error: '+str(e)) self.finish()
      
      





前の例とは異なり、返されるエラー値を毎回確認する必要はありません。代わりに例外がスローされます。 (再度、例外チェックを行う必要があります:)



試してみたい人は、tornadomongoモジュールがここにあります:hg clone bitbucket.org/lega911/tornadomongo

その中で、例外を作成できるようにするために、このモジュールを実験のみに使用できるようにするために、トルネードモジュールに「ダーティインジェクション」を作成する必要がありました。



1つのプロジェクトのいくつかのモジュールをtornado.genに既に変換しました。その結果、コードの量が減少し、コードの可読性が(同じ機能の)増加しました。



PS:この記事の執筆時点では、モジュールはドキュメントに記載されていませんでしたが、現在投稿されています: www.tornadoweb.org/documentation/gen.html



All Articles