web-dev-qa-db-ja.com

ウェイトレスは並行タスクをどのように処理しますか?

pythonウェブサーバーをDjangoとウェイトレスを使用して構築しようとしていますが、ウェイトレスが同時リクエストを処理する方法とタイミングblockingが発生する場合があります。


Waitressのドキュメント は、複数のワーカースレッドが利用可能であると述べていますが、それらがどのように実装され、python GILがどのように影響するか)に関する多くの情報を提供していません(私自身の強調):

チャネルは、クライアントが少なくとも1つの完全な有効なHTTPリクエストを送信したと判断すると、「スレッドディスパッチャー」を使用して「タスク」をスケジュールします。スレッドディスパッチャーは、クライアントの作業に使用できるワーカースレッドの固定プールを維持します(デフォルトでは4スレッド)。タスクのスケジュール時にワーカースレッドが使用可能な場合、ワーカースレッドはタスクを実行します。タスクはチャネルにアクセスでき、チャネルの出力バッファに書き戻すことができます。 すべてのワーカースレッドが使用中の場合、スケジュールされたタスクはキューで待機しますワーカースレッドが使用可能になる。

Stackoverflowについてもあまり情報がないようです。質問から "Gunicornのgthread非同期ワーカーはウェイトレスに類似していますか?"

ウェイトレスには、リクエストをバッファリングするマスター非同期スレッドがあり、リクエストI/Oが完了すると、各リクエストを同期ワーカースレッドの1つにエンキューします。


これらのステートメントは(少なくとも私の理解からは)GILに対応していません。誰かがウェイトレスでワーカースレッドがどのように機能するかについて詳しく説明できればすばらしいと思います。ありがとう!

9
MoltenMuffins

イベント駆動型非同期サーバーが一般的に機能する方法を次に示します。

  • プロセスを開始し、着信要求を待機します。オペレーティングシステムのイベント通知APIを利用すると、数千のクライアントに単一のスレッド/プロセスから非常に簡単にサービスを提供できます。
  • すべての接続を管理するプロセスは1つしかないので、このプロセスで遅い(またはブロックする)タ​​スクを実行する必要はありません。それはそれがすべてのクライアントのプログラムをブロックするからです。
  • ブロックタスクを実行するために、サーバーはタスクを「ワーカー」に委任します。ワーカーは、スレッド(同じプロセスで実行中)または個別のプロセス(またはサブプロセス)になります。これで、メインプロセスは、ワーカーがブロッキングタスクを実行している間もクライアントにサービスを提供し続けることができます。

ウェイトレスはどのように並行タスクを処理しますか?

上記で説明したのとほとんど同じです。そして、ワーカーのために、プロセスではなくスレッドを作成します。

python GILによる影響

ウェイトレスはワーカーにスレッドを使用します。だから、はい、彼らはGILの影響を受けています。 「非同期」が正しい用語です。

Python=のスレッドは、単一のプロセス内、単一のCPUコアで実行され、並行して実行されません。スレッドは非常に短い時間でGILを取得し、そのコードを実行してから、 GILは別のスレッドによって取得されます。

ただし、GILはネットワークI/Oで解放されるため、ネットワークイベント(着信要求など)があると、親プロセスは常にGILを取得します。これにより、GILがネットワークにバインドされた操作に影響しないことを保証できます(リクエストの受信やレスポンスの送信など)。

一方、Pythonプロセスは実際には同時実行です。複数のコアで並行して実行できますが、ウェイトレスはプロセスを使用しません。

気になりますか?

データベースの読み取り/書き込みなどの小さなブロックタスクを実行し、1秒あたり数百のユーザーしか処理しない場合、スレッドの使用はそれほど悪いことではありません。

大量のユーザーにサービスを提供したり、長時間実行するブロッキングタスクを実行したりするには、 Celery のような外部タスクキューの使用を検討します。これは、自分でプロセスを生成して管理するよりもはるかに優れています。

2
xyres