1

次の問題があります。

私はトルネード ベースのアプリケーション サーバーで作業しています。ほとんどのコードは同期可能であり、Web インターフェースは Tornado の非同期機能をまったく使用していません。

tornado.iostreamコマンドを送信するためにインターフェイスを使用する (非同期) レガシー バックエンドにインターフェイスする必要があります。これらのコマンドへの応答は、ステータス更新などの他の定期的な情報とともに非同期で送信されます。

コードは、他のバックエンドにも使用される共通のインターフェイスにラップされています。

私が達成したいことは次のとおりです。

# this is executed on initialization
self.stream.read_until_close(self.close, self.read_from_backend)

# this is called whenever data arrives on the input stream
def read_from_backend(self, data):
     if data in pending:
         # it means we got a response to a request we sent out
         del self.pending[data]
     else:
         # do something else

# this sends a request to the backend
def send_to_backend(self, data):
     self.pending[data] = True
     while data in self.pending:
          # of course this does not work
          time.sleep(1)
     return 

もちろん、これ以上実行できないため、これは機能しませtime.sleep(1)read_from_backend()

これを解決するにはどうすればよいですか?send_to_backend()応答が受信された場合にのみ返されるようにします。read_from_backendメソッドからまだ戻らずに制御を譲ることができる方法はありますか?

@asynchronous と @gen.engine を使用して Web レイヤーでこれを行うのは難しいことに注意してください。これは、Web レイヤーのすべてのリクエストを完全に書き直す必要があるためです。同じデザイン パターンを別の場所に実装する方法はありますか?

4

1 に答える 1

1

gevent の使用を検討することをお勧めします。MonkeyPatching と私が書いた単純なデコレータを使用することで、同期方式 (ブロッキング スタイル) で記述された非常に簡単に素敵な非同期ビューを取得できます。

私の以前の回答からほとんどのコードを再利用できます。

さまざまな理由で gevent を使用したくない場合がありますが (依存関係がないため):

グローバルプロセスに次のパッチを適用したことを認めます。

from gevent import monkey; monkey.patch_all()

上記は、スレッド、ソケット、スリープにパッチを適用するため、それらは gevent のハブを通過します (ハブは、ioloop が tornado にあるものを gevent にします)。

パッチを適用し、以前の回答で @gasync デコレータを使用すると、ビューは次のようになります。

class MyHandler(tornado.web.RequestHandler):
     @gasync
     def get(self):
         # Parse the input data in some fashion
         data = get_data_from_request()

         # This could be anything using python sockets, urllib ...
         backend_response = send_data_to_backend(data)

         # Write data to HTTP client
         self.write(backend_response)

         # You have to finish the response yourself since it's asynchronous
         self.finish()

gevent のシンプルさと「エレガンス」は、tornado の ioloop を使用して非同期コードを作成する利点よりもはるかに優れていることがわかりました。

私の場合、同期方式で記述されたレガシー コードを使用する必要があったため、基本的に gevent の方が安全でした。モンキー パッチを適用してそのデコレータを作成するだけで、レガシー コードを変更せずにすべて使用できました。

これが役立つことを願っています。

于 2012-11-10T12:13:25.133 に答える