非ブロッキング受信がメッセージパッシングであまり使用されていないことは知っていますが、それでもいくつかの直感は、それが必要であることを教えてくれます。GUIイベント駆動型アプリケーションを例にとると、プログラムが計算を実行できるように、ブロックしない方法でメッセージを待つ何らかの方法が必要です。これを解決する方法の 1 つは、メッセージ キューを持つ特別なスレッドを用意することです。スレッドがある場合でも、非ブロッキング受信が本当に必要になるユースケースはありますか?
6 に答える
スレッドは、非ブロッキング非同期操作とは異なる動作をしますが、同期操作を行うスレッドを使用することで、通常は同じ効果を得ることができます。ただし、最終的には、物事をより効率的に処理する方法に要約されます。
スレッドは限られたリソースであり、実行時間の長いアクティブな操作を処理するために使用する必要があります。実際にはアクティブではないものの、結果が出るまでしばらく待つ必要がある場合 (Web サービスやデータベース サーバーの呼び出しなど、ネットワークを介した I/O 操作を考えてください)、提供された を使用することをお勧めします。同期呼び出しを別のスレッドに置いてスレッドを不必要に浪費する代わりに、非同期の代替手段を使用します。
この問題については、こちらをよく読んで理解を深めてください。
多くの場合、接続ごとに 1 つのスレッドを使用することはお勧めできません (メモリの浪費、すべての OS が非常に優れているわけではないなど)。
ブロッキング受信呼び出しをどのように中断しますか? たとえば、Linux では (おそらく他の POSIX OS でも)、pthreads + シグナル = 惨事です。ノンブロッキング受信を使用すると、受信ソケットと、スレッド間の通信に使用されるある種の IPC ソケットでの待機を多重化できます。Windows の世界にも比較的簡単にマップできます。
通常のソケットをより複雑なもの (OpenSSL など) に置き換える必要がある場合、ブロッキング動作に依存すると問題が発生する可能性があります。たとえば、OpenSSL はブロッキング ソケットでデッドロックになる可能性があります。これは、SSL プロトコルには、送信が完了する前に受信を続行できない送信者/受信反転シナリオがあるためです。
私の経験は、「疑わしい場合はノンブロッキングソケットを使用する」ことです。
ブロッキング IO を使用すると、多くのプラットフォームで、低速、ハング、または切断されたクライアント/サービスに直面して、アプリケーションにベスト エフォートの正常なシャットダウンを実行させることが困難になります。
ノンブロッキング IO を使用すると、システム コールが返されるとすぐに実行中の操作を強制終了できます。コードが早期終了を念頭に置いて書かれている場合 (ノンブロッキング IO では比較的単純です)、これにより、保存された状態を適切にクリーンアップできます。
思いつきませんが、非ブロッキング API は、明示的にマルチスレッド化された実装よりも使いやすく/直感的になるように設計されている場合があります。
ここに私が最近直面した実際の状況があります。以前は、crontab で管理された 1 時間ごとに実行されるスクリプトがありましたが、ユーザーがマシンにログインしてスクリプトを手動で実行することもありました。これにはいくつかの問題がありました。たとえば、crontab とユーザーによる同時実行が問題を引き起こす可能性があり、ユーザーが root としてログインすることもありました (私の制御下にない悪いパターンです)。スクリプトを間違った権限で実行します。そのため、ルーチンをデーモンとして実行し、適切なパーミッションを設定することにしました。これにより、ユーザーが実行していたコマンドがデーモンをトリガーするだけになりました。
したがって、このユーザーが実行するコマンドは、基本的に 2 つのことを行います。デーモンをトリガーし、デーモンがタスクを終了するのを待ちます。ただし、タイムアウトが必要であり、待機中にデーモンログをユーザーにダンプし続ける必要がありました。
あなたが提案した状況を理解していれば、あなたが望むケースがありました.ユーザーと個別に対話しながら、デーモンからリッスンし続ける必要がありました. 解決策は非同期読み取りでした。
幸運なことに、スレッドの使用については考えていませんでした。Java でコーディングしていたらそう思ったかもしれませんが、これは Python コードでした。
私が言いたいのは、スレッドとメッセージングが完璧であると考えるとき、本当のトレードオフは、ノンブロッキング受信操作を計画するためのスケジューラーを書くことと、共有状態 (ロックなど) を持つスレッドの同期コードを書くことです。どちらも簡単な場合もあれば、難しい場合もあります。したがって、非同期メッセージを受信するメッセージが多く、メッセージに基づいて操作するデータが多い場合がユース ケースとなります。これは、非ブロッキング受信を使用する 1 つのスレッドでは非常に簡単であり、多くのスレッドと共有状態との多くの同期を要求します....私は実際の例についても考えています。おそらく後で含めます。