プライベートな連絡先の最初の情報
送料メール:
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
基本的な復習のために、NIO の基本的な知識を ava レベルで説明します。
Java では、NIO (ノンブロッキング I/O または New I/O) は、Java SE 1.4 以降のバージョンで導入された新しい入出力操作 API のセットです。
従来の IO モデルと比較して、より高い効率と優れた同時処理機能を提供します。 NIO の主な機能は、ノンブロッキング機能です。これにより、単一のスレッドで複数の I/O チャネルを管理できるようになり、同時実行性の高いシナリオでのアプリケーションのパフォーマンスが大幅に向上します。
Java NIO の使用シナリオは、多数の同時接続を処理する必要がある状況に特に適しています。たとえば、ネットワーク サーバーでは、接続ごとに独立したスレッドを割り当てる必要がなく、1 つのスレッドで数千のクライアント接続を管理できます。システムリソースの消費を大幅に削減し、処理能力を向上させることができます。
チャネルは Java NIO のデータ フローの媒体であり、双方向であり、データの読み取りまたは書き込みに使用できます。チャネルの主な利点は、チャネルが非ブロックであることです。つまり、チャネルでイベントが発生しない場合、スレッドはブロックされず、代わりに他のタスクを処理できます。主なチャネルの種類は次のとおりです。
FileChannel
: ファイルの読み取りおよび書き込み操作に使用され、バッファーからファイルへのデータの書き込み、またはファイルからバッファーへのデータの読み取りに使用できます。SocketChannel
:ネットワーク通信におけるTCP接続に使用され、データの読み書きに使用できます。ServerSocketChannel
: 従来の ServerSocket と同様に、新しい SocketChannel 接続を受け入れるために使用されます。DatagramChannel
: データグラムを送受信できる UDP 通信に使用されます。バッファは、NIO にデータを保存するために使用されるオブジェクトであり、データの書き込みと読み取りを行うことができます。バッファには特定の容量があり、位置と制限という 2 つの重要なプロパティがあります。
バッファの主な種類は次のとおりです。ByteBuffer
、CharBuffer
、ShortBuffer
、IntBuffer
、LongBuffer
、FloatBuffer
そしてDoubleBuffer
、各型はプリミティブ データ型に対応します。
セレクターは、NIO のマルチプレクサーで、単一のスレッドが読み取り、書き込み、接続、イベントの受信など、複数のチャネルからのイベントを監視できるようにします。セレクターは、チャネルの 1 つが I/O 操作の準備ができたときにアプリケーションに通知します。セレクターを使用すると、接続ごとにスレッドを作成する必要がないため、ネットワーク アプリケーションの同時処理能力が大幅に向上します。
セレクターの主なメソッドは次のとおりです。
select()
: 少なくとも 1 つのチャネルが I/O 操作の準備ができるまでブロックします。selectedKeys()
: 準備されたすべてのチャネルの SelectionKey オブジェクトを含む Set を返します。wakeup()
: 割り込みがブロックされていますselect()
移行。SelectionKey
これは、セレクターとチャネルの間の関連付けであり、チャネル、セレクター、対象イベント コレクション、準備完了イベント コレクションなど、セレクター上のチャネルの登録ステータスを表します。
これは最も伝統的な I/O モデルであり、Java では、従来の Socket API と ServerSocket API はブロッキング I/O に基づいています。このモードでは、スレッドが読み取りまたは書き込み操作を開始すると、I/O 操作が完了するまでスレッドはブロックされます。読み取り操作で読み取るデータがない場合、または書き込み操作をすぐに完了できない場合、スレッドは操作が完了するまで待機します。
特徴:
ノンブロッキング I/O は Java NIO (New I/O) フレームワークの一部であり、スレッドがブロックされることなく読み取りおよび書き込み操作を開始できるようにします。読み取り操作で読み取るデータがない場合、または書き込み操作をすぐに完了できない場合、スレッドは中断されず、他のタスクの実行を続行できます。
特徴:
多重化とは、1 つのスレッドを通じて複数のファイル記述子を同時に監視し、準備ができたときにのみ記述子を操作することです (通常、データが読み取り可能であるか、書き込みバッファーが書き込み可能であることを意味します)。 Java ではセレクターを使用して多重化を実装します。
特徴:
知らせ:
実際のアプリケーションでは、ノンブロッキング I/O が多重化と組み合わせて使用されることがよくあります。たとえば、サーバーはセレクターを使用して複数の SocketChannel を監視できます。SocketChannel に読み取りまたは書き込み可能なデータがある場合、セレクターはサーバーに通知し、サーバーはこの特定の SocketChannel を非ブロック方式で処理します。
Java では、ストリームとチャネルはデータ ストリームを処理する 2 つの異なる方法で、それぞれ Java の標準 IO ライブラリと NIO ライブラリに属します。 2 つの概念の詳細な比較は次のとおりです。
ストリームは Java の標準 IO (ブロッキング IO) モデルの一部であり、データを順次読み書きする方法を提供します。 ストリームは、InputStream と OutputStream の 2 種類に分けられ、それぞれデータの読み取りと書き込みに使用されます。これらのストリームはバイト ストリーム (たとえば、InputStream
, OutputStream
) または文字ストリーム (例:Reader
, Writer
)。
特徴:
close()
リソースを解放するメソッド。Java 7 以降、try-with-resources ステートメントは実装を自動的に閉じることができます。AutoCloseable
ストリームを含むインターフェイス リソース。チャネルは Java NIO (New IO) モデルの一部であり、ストリームよりも高いレベルの抽象化を提供し、より効率的なデータ処理を可能にします。 チャネルは双方向にすることができます。つまり、データの読み取りと書き込みに使用できます。主なチャネル タイプには次のものがあります。FileChannel
、SocketChannel
、ServerSocketChannel
そしてDatagramChannel
。
特徴:
要約する
Java では、I/O 操作モデルは、同期/非同期、およびブロッキング/ノンブロッキングの 2 つの次元に基づいて分類できます。
意味 : 同期ブロッキング I/O は、スレッドが I/O 操作 (読み取りや書き込みなど) を呼び出すと、その操作が完了するまでブロックされます。これは、操作が完了するまでスレッドは他のタスクを実行できないことを意味します。
特徴:
InputStream
、OutputStream
、Socket
そしてServerSocket
シーン。例:
従来のものを使用するInputStream
そしてOutputStream
ファイルの読み取りと書き込みを行うには:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class SyncBlockingIOExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt")) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
意味 : 同期ノンブロッキング I/O では、I/O 操作の呼び出し後にスレッドはブロックされません。操作をすぐに完了できない場合、メソッドはすぐに戻り、通常は特別な値 (-1 や 0 など) を返すか、操作が完了していないことを示す例外をスローします。
特徴:
Channels
そしてBuffers
、電話することでconfigureBlocking(false)
チャネルをノンブロッキング モードに設定します。例:
NIO の使用FileChannel
ノンブロッキングの読み取りおよび書き込みの場合:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;
public class SyncNonBlockingIOExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt");
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
inChannel.configureBlocking(false);
while (inChannel.read(buffer) > 0) {
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
意味: 同期多重I/Oモデルの使用方法Selector
(セレクター) 複数を監視する場合Channel
イベント。スレッドが呼び出すときSelector.select()
、少なくとも 1 つ存在するまでブロックされます。Channel
イベント(読み取り可能、書き込み可能、接続要求など)が発生します。
特徴:
Channel
、同時実行性が向上します。Selector
そしてSelectionKey
大量の同時接続を効率的に処理できる仕組み。例:
NIO の使用FileChannel
ノンブロッキングの読み取りおよび書き込みの場合:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
public class SyncMultiplexingIOExample {
public static void main(String[] args) throws IOException {
try (Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
if (selector.select() > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = ssc.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
}
}
keys.clear();
}
}
}
}
}
意味 : 非同期ノンブロッキング I/O モデルでは、スレッドは I/O 操作の開始後、操作の完了を待たずにすぐに戻ります。操作が完了すると、コールバック関数またはイベント通知を通じてスレッドに非同期に通知されます。
特徴:
AsynchronousChannel
インターフェイスとそのサブクラスの実装 (例:AsynchronousFileChannel
そしてAsynchronousSocketChannel
。例:
NIO の使用AsynchronousFileChannel
非同期ファイルの読み取りと書き込みを実行します。
import java.io.IOException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
public class AsyncNonBlockingIOExample {
public static void main(String[] args) throws IOException, InterruptedException {
AsynchronousFileChannel inChannel = AsynchronousFileChannel.open(Paths.get("input.txt"), StandardOpenOption.READ);
AsynchronousFileChannel outChannel = AsynchronousFileChannel.open(Paths.get("output.txt"), StandardOpenOption.WRITE);
ByteBuffer buffer = ByteBuffer.allocate(1024);
CountDownLatch latch = new CountDownLatch(1);
inChannel.read(buffer, 0, buffer, 0, (channel, result) -> {
buffer.flip();
outChannel.write(buffer, 0, buffer, 0, null);
latch.countDown();
});
latch.await();
inChannel.close();
outChannel.close();
}
}
注: 非同期モデルには、基礎となるオペレーティング システム (カーネル) のサポートが必要です。
意味 : 「非同期」とは操作がバックグラウンドで実行され、スレッドがブロックされないことを意味するため、理論的にはこのモデルは存在しません。したがって、非同期ブロッキング I/O は矛盾した概念であり、実際には登場しません。
適切な I/O モデルを選択することは、パフォーマンスとリソース管理にとって重要です。同時実行性の高いシナリオでは、同期ノンブロッキング I/O モデルまたは同期多重化 I/O モデルが一般的に選択されます。極端なパフォーマンスと応答速度が必要なシナリオでは、非同期ノンブロッキング I/O モデルが最初の選択肢となります。
ゼロコピーのコンセプト
ゼロコピー テクノロジとは、ある場所から別の場所へのデータ送信プロセス中に、ユーザー空間とカーネル空間の間でデータをコピーする必要がないか、少なくともコピーの数を減らすことで、データの効率が向上することを意味します。システム。従来の I/O 操作では、データがネットワークまたはディスクから読み取られると、まずカーネル空間のバッファにコピーされ、次にカーネル空間からユーザー空間のバッファにコピーされます。これに対し、ゼロコピーでは、データをカーネル空間で直接処理したり、カーネル空間からネットワークデバイスに直接転送したりできるため、CPU のコピー動作が減り、システムのオーバーヘッドが削減され、データ転送の効率が向上します。
ゼロコピーのソース
ゼロ コピーの概念は、従来の I/O 操作におけるデータ コピーによって引き起こされるパフォーマンスのボトルネックを解決することを目的として、オペレーティング システムの設計で初めて登場しました。初期のコンピュータ システムでは、すべての I/O 操作にユーザー空間とカーネル空間の間で複数のデータ コピーが必要でしたが、高速ネットワークと大容量ディスクが普及した後、これが徐々にパフォーマンスのボトルネックになりました。
技術的なポイント
Java での実装:
Java は、NIO (New I/O) フレームワークを通じてゼロコピー テクノロジをサポートします。 NIO導入FileChannel
そしてSocketChannel
および他のクラスは、より効率的な I/O 操作を提供します。具体的には、FileChannel.transferTo()
そしてFileChannel.transferFrom()
メソッドは、データをバッファにロードせずに、ファイル チャネルからソケット チャネルに、またはその逆にデータを直接転送できるため、ゼロ コピーを実現できます。
たとえば、大きなファイルの内容をネットワークに送信する必要があるとします。従来のアプローチでは、まずファイルの内容をバッファに読み取り、次にバッファの内容をネットワークに書き込みます。これには 2 つのコピー操作が含まれます。1 つはディスクからバッファーへ、もう 1 つはバッファーからネットワークへです。使用中transferTo()
この方法を使用すると、中間バッファを必要とせずにデータをディスクからネットワークに直接転送できるため、コピー数が削減され、コピーゼロが実現します。
ByteBuffer を使用した例:
ByteBuffer
その他Buffer
クラス(など)CharBuffer
,ShortBuffer
など) ユーザー空間とカーネル空間の間のコピーを直接関与させることなく、埋めたり空にしたりできるバッファーを提供します。ByteBuffer
ゼロコピーテクノロジーで直接的または間接的に使用できます。
ByteBuffer.allocateDirect(size)
作成したByteBuffer
インスタンスは Java ヒープをバイパスして、物理メモリに直接マッピングされます。このようなバッファを比較すると、FileChannel
またはSocketChannel
一緒に使用すると、Java ヒープを介して追加のコピーを必要とせずに、物理メモリとハードウェア デバイスの間でデータを直接転送できます。これにより、一部のプラットフォームで真のゼロコピーが可能になります。FileChannel
のtransferTo()
そしてtransferFrom()
: これらの方法では、データを直接保存できます。FileChannel
そしてSocketChannel
間で送信されるByteBuffer
仲介者として。これは、ユーザー空間とカーネル空間の間でデータをコピーすることなく、データをディスクからネットワークに、またはその逆に直接転送できることを意味します。ByteBuffer
のwrap()
方法:wrap()
メソッドを使用すると、既存のバイト配列または他のバッファをラップすることができます。ByteBuffer
したがって、データを新しいバッファにコピーする必要はありません。これは、データの不必要なコピーを避けるのに役立ちます。ByteBuffer
のslice()
方法:slice()
このメソッドは、基礎となるデータをコピーせずにバッファーのビューを作成します。これは、大きなByteBuffer
データをコピーせずに複数の小さなバッファに分割します。ByteBuffer と FileChannel を結合します。
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
public class ZeroCopyExample {
public static void main(String[] args) {
Path path = Path.of("example.txt");
try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
long transferred = fileChannel.transferTo(0, fileChannel.size(), System.out);
System.out.println("Transferred bytes: " + transferred);
} catch (IOException e) {
e.printStackTrace();
}
}
}
知らせ:
実際には、完全なゼロ コピーは存在しないことに注意してください。ここで説明するゼロ コピーは、ユーザー レベルのコピーを持たないアプリケーション自体のみを対象としています。しかし、ユーザーレベルでも、コピー操作をまったく行わないことは不可能ですが、コピーを可能な限り減らすことは不可能です。したがって、ゼロコピーという用語は、実際にはデータのコピー数を減らす技術を指すことがわかります。実際のコピー操作が存在しないという意味ではありません。