0

私が知っているように、最も一般的な JVM 同時実行 API の 1 つである先物 (少なくとも scala で実装されているもの) は、アイドル状態で待機する可能性がある場合に、ユーザー コードに依存してスレッドを放棄します。scala では、これは一般に「ブロッキングの回避」と呼ばれ、開発者は意味のあるあらゆる場所に実装する必要があります。あまり効率的ではありません。

オペレーティング システム プロセス スケジューラによって実装されているように、スレッドがアイドル状態のときに、JVM がスレッドのコンテキストを新しいタスクに切り替えるのを防ぐ、JVM に完全に固有の何かがありますか?

4

1 に答える 1

0

オペレーティング システム プロセス スケジューラによって実装されているように、スレッドがアイドル状態のときに、JVM がスレッドのコンテキストを新しいタスクに切り替えるのを防ぐ、JVM に完全に固有の何かがありますか?

ほとんどの場合、そのような切り替えは協力して行う必要があります。すべてのブロッキング メソッドは、タスクが完了したら再開できるようにラップまたは再実装する必要があります。結局のところ、ブロッキング アクションの完了を待っているネイティブ スレッドはもうありません。

これは原則として JVM 内部ブロッキング メソッドに対して実行できますが、JNI を介して実行される任意のネイティブ コードを考えてみてください。JVM はそれらのネイティブ スレッドをスタック切り替えする方法を認識せず、最終的にネイティブ コードでスタックします。

quasarを見たいと思うかもしれませんがsleep、 、park/ unpark、 channel-based-IOなどの一部の JDK 内部メソッドのようなラッパーまたは同等のものを実装し、それらのファイバー (したがって先物これらのファイバーで実行されている) を使用して、完了を待機している間にまさにその種類のユーザー モード コンテキスト切り替えを実行します。

編集:ネイティブ コードがスレッドをブロックするときに、追加のネイティブ スレッドをスピンアップするためにフォールバックしなければならない可能性がある日和見的な最適化にユーザー モードのタスク切り替えを制限するには、 JNI だけですでに十分です。

しかし、それだけの問題ではありません。たとえば、Linux では真に非同期のファイル IO 操作には、ファイルシステムとカーネルのサポートが必要です ( AIO に関するこの SO の質問を参照)。すべてが提供するわけではありません。提供されていない場合は、追加のブロッキング IO スレッドを使用してエミュレートする必要があるため、最初に回避したかったすべてのオーバーヘッドが再び発生します。スレッドプール自体をブロックして、追加のスレッドをスピンアップすることもできますが、少なくともそのようにしてスレッド間通信を回避します。

メモリ マップ ファイルもスレッドをブロックし、ページ フォールトが原因で OS スケジューラが強制的にスレッドを一時停止する可能性がありますが、それを回避するために仮想メモリ システムと連携する手段を私は知りません。

言うまでもなく、VM でのすべてのブロッキング呼び出しは、OS によって提供される非同期の同等のものを使用して再実装する必要があります。1 つでも見逃すと、スレッドがブロックされます。ブロックされたスレッドがある場合、スレッド プールには自動拡張機能が必要になり、振り出しに戻ります。

最後になりましたが、ブロッキング、ファイル記述子ごとに 1 スレッドの IO が望ましい場合があります。ユーザーモードの切り替えを保証するために必要な広範な変更により、それらが壊れる可能性があります。

全体として、ユーザーモードの切り替えが可能です。しかし、JVM はそれについて確固たる保証をすることはできないため、いずれにしてもすべてのネイティブ スレッド処理を実装する必要があり、プログラマーは、それらのフューチャーを実行するスレッド プールの仮定を念頭に置いて、少なくともいくらか協調的にコードを作成します。一部のケースは排除できますが、すべてではありません。

于 2015-03-30T21:11:12.593 に答える