10

私はフラスコを使用しており、一部のルート ハンドラーが計算を開始し、完了するまでに数分かかることがあります。フラスコの開発サーバーを使用して、 app.run(threaded=True) を使用できます。サーバーは、これらの数分間の計算を実行していない間、他のリクエストに応答し続けます。

今、私は Flask-SocketIO の使用を開始しましたが、同等のことを行う方法がわかりません。これらの計算のいずれかを開始するたびに、Python で別のスレッドを明示的に生成できることを理解しています。それが唯一の方法ですか?または、flask-socketio の threaded=True に相当するものはありますか。(または、おそらく、私は完全に混乱しています。)

助けてくれてありがとう。

4

1 に答える 1

22

Flask/Werkzeug のスレッド モードの考え方は、開発サーバーが複数の要求を同時に処理できるようにすることです。デフォルト モードでは、サーバーは一度に 1 つの要求を処理できます。サーバーが既に前の要求を処理しているときにクライアントが要求を送信した場合、2 番目の要求は最初の要求が完了するまで待機する必要があります。スレッド モードでは、Werkzeug は着信要求ごとにスレッドを生成するため、複数の要求が同時に処理されます。スレッド モードを利用して、サーバーが他の要求に応答できるようにしながら、返されるのに非常に時間がかかる要求を処理していることは明らかです。

このアプローチは、開発 Web サーバーから本番 Web サーバーに移動する場合、適切にスケーリングするのが難しいことに注意してください。ワーカーベースのサーバーの場合、固定数のワーカーを選択する必要があり、これにより、同時に実行できるリクエストの最大数が得られます。

もう 1 つの方法は、Flask で完全にサポートされている gevent などのコルーチン ベースのサーバーを使用することです。gevent には単一のワーカー プロセスがありますが、その中に複数の軽量 (または「グリーン」) スレッドがあり、協調して相互に実行できます。このモデルで物事を機能させるための鍵は、一度に実行できるのは 1 つのみであるため、これらのグリーン スレッドが取得した CPU 時間を乱用しないようにすることです。これが正しく行われると、サーバーは、上で説明した複数のワーカー アプローチよりもはるかに優れたスケーリングが可能になり、この方法で数百または数千のクライアントを簡単に処理できます。

Flask-SocketIO を使用する場合、この拡張機能には gevent を使用する必要があります。この要件の理由が明確でない場合、HTTP 要求とは異なり、SocketIO は WebSocket プロトコルを使用しますが、これには長時間の接続が必要です。gevent とグリーン スレッドを使用すると、潜在的に多数の常時接続クライアントを持つことが可能になります。これは、複数のワーカーでは不可能なことです。

問題は、gevent タイプのサーバーには適していない長い計算です。それを機能させるには、計算関数が頻繁に生成されるようにする必要があります。これにより、他のスレッドが実行されて枯渇しないようにすることができます。たとえば、計算関数にループがある場合、次のようにすることができます。

def my_long_calculation():
    while some_condition:
        # do some work here

        # let other threads run
        gevent.sleep()

このsleep()関数は基本的にスレッドを停止し、CPU を必要とする他のスレッドに切り替えます。最終的に制御が関数に戻され、その時点で次の反復に移ります。スリープ コールの間隔が広すぎたり (アプリケーションの残りの部分が応答しなくなるため)、近すぎたり (計算が遅くなる可能性があるため) しないようにする必要があります。

したがって、質問に答えるために、長い計算で適切に譲る限り、これは gevent の通常の動作モードであるため、同時要求を処理するために特別なことをする必要はありません。

何らかの理由で yield アプローチが不可能な場合は、CPU を集中的に使用するタスクを別のプロセスにオフロードすることを検討する必要がある場合があります。セロリを使用して、これらをジョブキューとして実行することもできます。

長々とした回答で申し訳ありません。お役に立てれば!

于 2015-06-18T18:35:33.963 に答える