![](https://habrastorage.org/getpro/habr/post_images/042/b0f/9c8/042b0f9c878726d652cf0dec6ad72be2.png)
ここでの成功要因は、ハードウェアサポートです。 SATA AHCI(Advanced Host Controller Interface)やNVMe(PCI Expressの不揮発性メモリインターフェイス)などのデバイスの大容量ストレージコントローラーは、かなり長いシーケンスの入出力操作を処理し、バスマスターモードでメインメモリとドライブ間でデータを移動できます。中央処理装置によって実行されるプログラムの参加なし。
![RAM内のAHCIドライバーによって生成され、コントローラーによってハードウェア解釈されるコマンドのリスト , AHCI](https://habrastorage.org/getpro/habr/post_images/937/df7/ea7/937df7ea72b64e7c683231efefb59956.png)
図1 RAMのAHCIドライバーによって生成され、ハードウェアのコントローラーによって解釈されるコマンド の リストには、最大32個のI / O操作記述子を含めることができます。 AHCI仕様の図
矛盾と決定
ここでは、2つの相互に矛盾する基準に基づいた、NIOフレームワークの別の、それほど明白ではないが、非常に重要な特性について説明します。
- 一方では、Javaはクロスプラットフォームプログラミング言語として、コンピューティングシステムのハードウェア特性、アーキテクチャ、さらにはCPU容量からも抽象化されています。 互換性には、アプリケーションプログラマを低レベルの詳細から確実に分離する一連の抽象化が必要です。 Javaでのポインターの不足を思い出すだけで十分です。
- 一方、パフォーマンスには、コードの詳細な最適化、特定の実行環境の仕様への適応、および使用するハードウェアのタイプが必要です。
Javaネイティブインターフェイス
1つの代替ソリューションは、Cまたはアセンブラーで記述されたJavaクラスとライブラリーをペアにすることです。 各オペレーティングシステムに対して標準化され、JVMとネイティブコード間の相互作用を提供するメカニズムによって補完される、従来の呼び出し規約に基づいて、 Java Native Interface ( JNI )を実装するネイティブクラスに言及するしかありません。 ちなみに、JNIテクノロジーを習得すると、ポインターにアクセスできますが、Javaにポインターがないと、不便な場合があります。
同時に、ネイティブコードの統合などの過激な方法を使用すると、Javaのクロスプラットフォームの利点がなくなり、アプリケーション開発の複雑さとエラーの可能性が劇的に増加します。 JNIソリューションでの複数のプラットフォームのサポートは、必然的に、サポートされるシステムの数に等しい数のライブラリのセットを作成および維持する必要があるforkコンストラクトを意味します。
確かに、JNIの使用が必要な状況があります。 たとえば、ハードウェア乱数ジェネレーターなどの一部の特別なデバイスのサポート。
NIO
結局のところ、プラットフォームのハードウェアリソースをカプセル化する抽象化システムを最適に設計すれば、Javaで高性能コードを開発することもできます。
ディスクからファイルを読み取る操作を検討してください。 プロセスには、データソース(ドライブまたはファイル)とレシーバー(RAMのバッファー)の2つの参加者がいることは明らかです。 以下はすべて、ファイルをディスクに書き込む場合に当てはまります。情報転送の方向のみが異なり、ソースと受信者は入れ替わります。
カスタムアプリケーションの場合、 ドライブまたはファイルはディスクI / O API関数で表されます。 互換性とセキュリティの明らかな理由により、MS-DOSの時代から過去から姿を消したユーザーアプリケーションを使用して、ディスクコントローラーのレジスタを直接プログラミングする可能性は考慮しません。
バッファは、アプリケーションのアドレス空間内の指定された範囲のメモリです。 多くの高レベルプラットフォームでは、
したがって、ハードウェアプラットフォームの対象オブジェクトは次のとおりです。
- ドライブまたはファイルとの通信チャネル(OS API)。
- RAM、バッファの範囲。
「客観的現実」の2つの名前付きコンポーネントに直接対応するJavaクラスを実装することにより、 チャネルとバッファーの概念に基づいたNIOフレームワークの開発者によって行われた補助操作の数を最小限に抑えることで、高性能ソリューションを得ることができます 。
もちろん、このようなツールは、低レベルのハードウェア依存プログラミングなしでは実装できません。 このツールを使用することで、アプリケーションプログラマがそのような必要性から救われると言うだけです。
NIOBenchユーティリティ
IC Book Labsによって開発され、マスストレージサブシステムのパフォーマンスを測定するように設計されたNIOBenchユーティリティは、ファイル操作を実行するときにチャネルとバッファを使用して言われたことを示しています。
![NIOBenchユーティリティ、ハードディスク上のファイルの読み取り、書き込み、コピーの速度を測定した結果の出力 NIOBench, ,](https://habrastorage.org/getpro/habr/post_images/51d/adb/484/51dadb48410ebeefc0a8adb09f72be55.png)
図2 NIOBenchユーティリティ、ASUS N750JKラップトップハードドライブでファイルの読み取り、書き込み、コピーの速度を測定した結果を表示(データ処理には中央値と算術平均が使用されます)
![結果の詳細なログを記録したNIOBenchテキストレポート NIOBench](https://habrastorage.org/getpro/habr/post_images/a2a/fbb/ddf/a2afbbddf20951b6d42e153c4f0c7176.png)
図3 結果の詳細なログを記録したNIOBenchユーティリティテキストレポート:キャッシュの効果は明らかです
入出力メソッド、特にベンチマークの対象となるファイルの読み取り、書き込み、コピー操作は、次のアーキテクチャ要素に基づいています。
- FileChannelオブジェクトは、読み取りまたは書き込みファイルから作成されたチャネルに対応します。 最も単純な読み取りおよび書き込み操作に加えて、 transferTo()、transferFrom()メソッドがサポートされ、ソースおよびレシーバーはファイルシステムオブジェクトになります。 この機能は、1つのJavaオペレーターでファイルの内容をコピーし、複数のバッファー間の不要なデータ転送を適切に取り除くことができるため、非常に重要です。 NIOフレームワークの特徴であるコピー方法の最適化の効率は、ベンチマークの開発とデバッグの過程でトリックを演じたことを認めなければなりません。測定されたコピー速度は、書き込み速度よりも高いことが判明しました。
- Bufferオブジェクトは、RAMの範囲に対応します。 この概念は自明ですが、データ転送の移動回数を最小限に抑えるために、 ByteBuffer.allocateDirect()メソッドを使用して直接バッファーを作成することをお勧めします。
この推奨事項に従わないと、Java抽象化を処理のためにAPI関数に渡されるネイティブオブジェクトに変換する必要があるため、パフォーマンスが低下する可能性があります。 JNIインターフェースは、NIOBenchプロジェクトでも使用され、RDRANDプロセッサ命令に基づいたハードウェア乱数ジェネレーターのサポートライブラリを接続します(この記事は 、執筆中の「Javaベンチマーク:ランダムパターンと通常の結果」です)。
まとめ
NIOテクノロジーの基礎であるチャネルとバッファの概念は、データストレージサブシステムのアーキテクチャに正確に対応しており、その主な機能はメインメモリ(バッファ)とさまざまなドライブ(チャネル)間の情報の移動に限定されます。
同時に、奇跡は起こらず、フレームワークを適用したプログラマーを解放する低レベルの作業は、フレームワークとシステムプログラマーの開発者にのみ譲渡されます...