この投稿ThreadingMixin
で、 (モジュールから)を使用して、を使用SocketServer
してスレッドサーバーを作成できることを読みましたBaseHTTPServer
。私はそれを試しました、そしてそれは働きます。ただし、サーバーによって生成されたアクティブなスレッドを停止するにはどうすればよいですか(たとえば、サーバーのシャットダウン中)?これは可能ですか?
2 に答える
最も簡単な解決策は、を使用することdaemon_threads
です。短いバージョンは次のとおりです。これをTrueに設定するだけで、心配する必要はありません。終了すると、まだ機能しているスレッドは自動的に停止します。
ThreadingMixIn
ドキュメントが言うように:
スレッド接続の動作のためにThreadingMixInから継承する場合は、突然のシャットダウン時にスレッドがどのように動作するかを明示的に宣言する必要があります。ThreadingMixInクラスは、サーバーがスレッドの終了を待機する必要があるかどうかを示す属性daemon_threadsを定義します。スレッドを自律的に動作させる場合は、フラグを明示的に設定する必要があります。デフォルトはFalseです。これは、ThreadingMixInによって作成されたすべてのスレッドが終了するまでPythonが終了しないことを意味します。
詳細については、threading
ドキュメントをご覧ください。
スレッドは「デーモンスレッド」としてフラグを立てることができます。このフラグの重要性は、デーモンスレッドのみが残っているときにPythonプログラム全体が終了することです。初期値は作成スレッドから継承されます。フラグはデーモンプロパティを介して設定できます。
終了せずにシャットダウンしたい場合や、ハンドラーにクリーンアップが必要な場合があるため、これが適切でない場合があります。しかし、それが適切である場合、これ以上単純なものを手に入れることはできません。
終了せずにシャットダウンする方法だけが必要であり、クリーンアップが保証されている必要がない場合は、ctypes
またはを介してプラットフォーム固有のスレッドキャンセルAPIを使用できる可能性がありますwin32api
。これは一般的に悪い考えですが、時にはそれがあなたが望むものです。
クリーンシャットダウンが必要な場合は、スレッドが連携する独自の機械を構築する必要があります。たとえば、で保護されたグローバルな「終了フラグ」変数を作成し、threading.Condition
関数にhandle
これを定期的にチェックさせることができます。
これは、スレッドが低速で非ブロッキングの作業を行っている場合に最適です。この作業は、細かく分割できます。たとえば、handle
関数が常に少なくとも5秒に1回は終了フラグをチェックする場合、5秒以内にスレッドをシャットダウンできることを保証できます。しかし、スレッドがブロッキング作業を行っている場合はどうなるでしょうか。おそらくそうですが、使用した理由は、ループを記述したり使用したりするのThreadingMixIn
ではなく、ブロッキング呼び出しを実行できるようにするためでした。select
asyncore
まあ、良い答えはありません。明らかに、「5秒以内」ではなく「最終的に」シャットダウンを実行する必要がある場合(または5秒後にクリーンシャットダウンを中止し、プラットフォーム固有のAPIを使用するか、スレッドをデーモン化することに戻る場合)、各ブロッキング呼び出しの前後にチェックを入れるだけで、「多くの場合」機能します。しかし、それだけでは不十分な場合、実際にできることは何もありません。
これが必要な場合、最善の答えは、これを行う方法があるフレームワークを使用するようにアーキテクチャを変更することです。最も人気のある選択肢は、、、Twisted
およびTornado
ですgevent
。将来的には、PEP 3156tulip
は同様の機能を標準ライブラリに導入する予定であり、すぐに準備が必要な現実の世界のために何かを構築しようとしない場合は、試してみる価値のある部分的に完全なリファレンス実装があります。
これは、threading.Eventを使用してPOSTリクエストでサーバーをシャットダウンする方法を示すサンプルコードです。
import SocketServer
import BaseHTTPServer
import threading
quit_event = threading.Event()
class MyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""This handler fires the quit event on POST."""
def do_GET(self):
self.send_response(200)
def do_POST(self):
quit_event.set()
self.send_response(200)
class MyThreadingHTTPServer(
SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
pass
server = MyThreadingHTTPServer(('', 8080), MyRequestHandler)
threading.Thread(target=server.serve_forever).start()
quit_event.wait()
server.shutdown()
サーバーは正常にシャットダウンされるため、「アドレスはすでに使用されています」を取得するのではなく、サーバーをすぐに再起動してポートを使用できます。