3

実行に時間がかかる関数があり、リクエストで実行する必要があります。このリクエストが処理中にメインスレッドをブロックしないようにするには、これに対処する最善の方法は何ですか? デコレータを見ました@tornado.web.asynchronousが、関数が非同期トルネード モジュールでない場合、ここではあまり役に立ちません。

class LongHandler(tornado.web.RequestHandler):
    def get(self):
        self.write(self.long_time_function())

    def long_time_function(self):
        time.sleep(5)
        return "foo"
4

2 に答える 2

7

非同期イベント ループで適切に動作しないブロッキング タスクがある場合は、別のスレッドに配置する必要があります。

ブロッキング タスクの数に制限がない場合は、スレッド プールを使用します。

いずれにせよ、スレッド化されたタスクからの通知をブロックするラッパー非同期タスクが必要です。

これを行う最も簡単な方法は、 tornado-threadpool のようなビルド済みライブラリを使用することです。* 次に、次のようにします。

class LongHandler(tornado.web.RequestHandler):
    @thread_pool.in_thread_pool
    def long_time_function(self, callback):
        time.sleep(5)
        callback("foo")

自分でやりたい場合は、この Gistに必要な作業の例を示します。もちろん、さまざまな Tornado スレッドプール ライブラリのソース コードをサンプル コードとして使用することもできます。

Python GIL の制限に注意してください。バックグラウンド タスクが CPU バウンドの場合 (そして、numpy のように GIL をリリースする C 拡張機能ではなく、Python でほとんどの作業を行う場合)、それを別のプロセス。Tornado プロセス プール ライブラリを簡単に検索しても、適切なオプションはあまり見つかりませんでしたが、スレッド プール コードをプロセス プール コードに適合させることは、通常、Python では非常に簡単です。**


* そのライブラリを特に推奨しているわけではないことに注意してください。これは Google 検索で最初に出てきたものにすぎず、一見しただけで使用可能で正しいように見えます。

** 多くの場合concurrent.futures.ThreadPoolExecutorconcurrent.futures.ProcessPoolExecutorまたはmultiprocessing.dummy.Poolで置き換えるだけmultiprocessing.Poolです。唯一の秘訣は、すべてのタスクの引数と戻り値が小さく、pickleable であることを確認することです。

于 2013-10-31T21:29:57.393 に答える
1

他の回答に記載されているように別のスレッドを使用することは、1つの方法です。関数をフラグメントに分割できる場合 (たとえば、内部に多くの反復を含むループがある場合) を使用して分割しIOLoop.add_callback()、他のリクエストの処理と計算を絡み合わせることもできます。これを行う方法の例を次に示します:コルーチンがトルネード インスタンス全体をブロックするのはなぜですか?

于 2013-10-31T21:36:01.650 に答える