web-dev-qa-db-ja.com

ノンブロッキングIO vs async IOと実装Java

これら2つの概念の違いを自分で要約しようとしています(人々が1つの文で両方を使用しているのを見ると本当に混乱します、「非ブロッキング非同期IO」のように平均)。

だから、私の理解では、ノンブロッキングIOは、IO準備ができているデータがある場合は、エラーを返す/何もしないで処理するOSメカニズムです。 。

Async IOでは、コールバックを提供するだけで、データが利用可能になるとアプリケーションに通知されます。

それでは、実際に「非ブロッキング非同期IO」とは何ですか?そして、それらすべてをJava(標準JDK、外部ライブラリなしで、私はJava.nio.channels.{Channels, Selector, SelectorKey}およびJava.nio.channels.{AsynchronousSocketChannel}):非ブロッキングIO、非同期IO、および非ブロッキング非同期IO(そのようなことがある場合)?

61
akazlou

では、実際に「非ブロッキング非同期IO」とは何ですか?

それに答えるには、最初にblocking async I/Oのようなものがないことを理解する必要があります。非同期の概念そのものが、待機、ブロッキング、遅延がないことを示しています。 非ブロッキング非同期I/Oが表示されている場合、non-blockingビットは、その用語のasync形容詞をさらに修飾するためだけに使用されます。つまり、事実上、非ブロッキング非同期I/Oは冗長性が少しあるかもしれません。

主に2種類のI/Oがあります。 同期および非同期同期は、処理が完了するまで現在の実行スレッドをブロックします非同期は現在の実行スレッドをブロックしませんではなく、OSカーネルに制御を渡してさらに処理します。カーネルは、送信されたタスクが完了すると、非同期スレッドに通知します


非同期チャネルグループ

Javaの非同期チャネルの概念は、非同期チャネルグループによって支えられています。非同期チャネルグループは、基本的に再利用のために多数のチャネルをプールします。非同期APIのコンシューマは、グループ(JVMデフォルトで作成されます)、チャネルは読み取り/書き込み操作が完了すると自動的にグループに戻ります。最終的に、非同期チャネルグループはsurprise、threadpoolsによってバックアップされます。また、非同期チャネルはスレッドセーフです。

非同期チャネルグループをバッキングするスレッドプールのサイズは、次のJVMプロパティによって構成されます

Java.nio.channels.DefaultThreadPool.initialSize

整数値を指定すると、そのサイズのスレッドプールがセットアップされ、チャネルグループがバックアップされます。それ以外の場合、チャネルグループは作成者に透過的に作成され、維持されます。


そして、それらすべてをJavaで実装する方法

まあ、あなたが尋ねてくれてうれしいです。 AsynchronousSocketChannel(非ブロッキングクライアントSocketをリスニングサーバーに開くために使用)の例を次に示します。このサンプルは Apress Pro Java NIO.2 、私がコメント:

//Create an Asynchronous channel. No connection has actually been established yet
AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open(); 

/**Connect to an actual server on the given port and address. 
   The operation returns a type of Future, the basis of the all 
   asynchronous operations in Java. In this case, a Void is 
   returned because nothing is returned after a successful socket connection
  */
Void connect = asynchronousSocketChannel.connect(new InetSocketAddress("127.0.0.1", 5000)).get();


//Allocate data structures to use to communicate over the wire
ByteBuffer helloBuffer = ByteBuffer.wrap("Hello !".getBytes()); 

//Send the message

Future<Integer> successfullyWritten=  asynchronousSocketChannel.write(helloBuffer);

//Do some stuff here. The point here is that asynchronousSocketChannel.write() 
//returns almost immediately, not waiting to actually finish writing 
//the hello to the channel before returning control to the currently executing thread

doSomethingElse();

//now you can come back and check if it was all written (or not)

System.out.println("Bytes written "+successfullyWritten.get());

編集:Async NIOのサポートはJDK 1.7で提供されたことに言及する必要があります

49
kolossus

これは古い質問ですが、@ nickduが指摘しようとしたものの、明確ではなかったものがここで見逃されたと思います。

この議論に関連するIOには4つのタイプがあります。

ブロッキングIO

非ブロッキングIO

非同期IO

非同期の非ブロッキングIO

定義があいまいであるため、混乱が生じると思います。それでそれを明確にしようとします。

最初にIOについて説明しましょう。遅いIOがある場合、これは最も明白ですが、IO操作はブロッキングまたは非ブロッキングのいずれかです。これはスレッドとは関係なく、オペレーティングシステムへのインターフェイスと関係があります。 OSにIO操作を要求するとき、すべてのデータの準備ができるのを待つか(ブロッキング)、すぐに利用できるものを取得して先に進むか( 非ブロッキング)。デフォルトはIOのブロックです。パスがはるかに明確であるため、ブロッキングIOを使用してコードを記述する方がはるかに簡単です。ただし、コードは停止し、IOが完了するのを待つ必要があります。ノンブロッキングIOは、便利な操作を提供する高レベルのライブラリの代わりに選択および読み取り/書き込みを使用して、低レベルのIOライブラリとインターフェイスする必要があります。非ブロッキングIOは、OSがIOを実行している間に作業する必要があるものがあることも意味します。これは、複数のIO操作または完了したIOの計算である可能性があります。

Blocking IO-アプリケーションは、OSがすべてのバイトを収集して操作を完了するか終了するまで待機してから続行します。これがデフォルトです。非常に技術的にわかりやすいように、IOを開始するシステムコールは、IO操作が進行するときに発生するプロセッサ割り込みを待機するシグナルハンドラをインストールします。その後、システムコールはスリープを開始し、現在のプロセスの動作を一定期間、またはプロセス割り込みが発生するまで一時停止します。

Non-Blocking IO-アプリケーションは、現在使用可能なバイトのみを必要としていることをOSに伝え、OSが同時により多くのバイトを収集する間、移動します。コードはselectを使用して、使用可能なバイトがあるIO操作を判別します。この場合、システムコールは再びシグナルハンドラをインストールしますが、スリープするのではなく、シグナルハンドラをファイルハンドルに関連付けて、すぐに戻ります。プロセスは、設定されている割り込みフラグのファイルハンドルを定期的にチェックする責任を負います。これは通常、select呼び出しで行われます。

非同期が混乱の始まりです。非同期の一般的な概念は、バックグラウンド操作が実行されている間、プロセスが継続することのみを意味し、これが発生するメカニズムは特定ではありません。非ブロッキングIOとスレッドブロッキングIOの両方が非同期であると見なされるため、この用語はあいまいです。どちらも同時操作を許可しますが、リソース要件は異なり、コードは大幅に異なります。 「非ブロッキング非同期IOとは何か」という質問をしたので、非同期の厳密な定義を使用します。スレッドシステムは、非ブロックの場合とそうでない場合があるIOを実行します。

一般的な定義

非同期IO-複数の同時IO操作を発生させるプログラムIO。 IO操作が同時に発生しているため、コードは準備ができていないデータを待機していません。

より厳密な定義

非同期IO-スレッド化またはマルチプロセッシングを使用して同時IO操作を発生させるプログラムIO。

これらのより明確な定義により、次のfourタイプのIOパラダイムがあります。

ブロッキングIO-標準のシングルスレッドIOでは、アプリケーションはすべてのIO操作が完了するまで待機してから次に進みます。コーディングが簡単で、同時実行性がないため、複数のIO操作が必要なアプリケーションの場合は非常に遅くなります。 IO割り込みの発生を待機している間、プロセスまたはスレッドはスリープします。

非同期IO-スレッドIO。アプリケーションが実行のスレッドを使用して、ブロッキングIO操作を同時に実行します。スレッドセーフコードが必要ですが、一般的には、代替よりも読み書きが簡単です。複数のスレッドのオーバーヘッドを取得しますが、実行パスは明確です。同期されたメソッドとコンテナの使用が必要になる場合があります。

非ブロッキングIO-シングルスレッドIOは、アプリケーションがselectを使用してどのIO操作を進める準備ができているかを判断し、他のコードの実行またはOSが並行IOを処理している間のその他のIO操作。プロセスはIO割り込みを待機している間はスリープしませんが、ファイルハンドルのIOフラグをチェックする責任を負います。 selectでIOフラグをチェックする必要があるため、はるかに複雑なコードですが、スレッドセーフコードまたは同期メソッドとコンテナは必要ありません。コードの複雑さを犠牲にしてオーバーヘッドを低く抑えます。実行パスは複雑です。

非同期非ブロックIO-可能な場合は非ブロックIO操作を使用してスケーラビリティを維持しながら、スレッドを使用して複雑さを軽減することを目的としたIOへのハイブリッドアプローチ。これは、同期されたメソッドとコンテナ、および複雑な実行パスを必要とするIOの最も複雑なタイプです。これはIOのタイプではなく、コーディングを軽視する必要があり、ほとんどの場合、Futures and Promisesなどの複雑さをマスクするライブラリを使用する場合にのみ使用されます。

86
AaronM

Ioには3つのタイプがあります。

同期ブロッキング
同期ノンブロッキング
非同期

同期非ブロッキングと非同期は、呼び出しスレッドがIOの完了を待機していないため、非ブロッキングと見なされます。したがって、非ブロッキング非同期ioは冗長ではありますが、1つではありませんファイルを開くとき、非ブロッキングモードで開くことができますこれはどういう意味ですか?read()を発行してもブロックされないことを意味します。非ブロッキングioを有効にしなかった場合、データが利用可能になるまでread()はブロックします。複数のioリクエストを処理するスレッドが必要な場合は、非ブロッキングioを有効にしたい場合があります。たとえば、select()を使用して、読み取り可能なデータがあるファイル記述子(またはソケット)を見つけることができます。その後、それらのファイル記述子で同期読み取りを実行します。ファイル記述子を非ブロックモードで開きました。

非同期ioは、io要求を発行する場所です。その要求はキューに入れられるため、発行スレッドをブロックしません。要求が失敗したか、正常に完了したときに通知されます。

4
nickdu

非ブロッキングIOは、IOを実行する呼び出しがすぐに返され、スレッドをブロックしません。

IOが完了したかどうかを知る唯一の方法は、そのステータスまたはブロックをポーリングすることです。Futureと考えてください。IO操作であり、Futureを返します。isDone()を呼び出して、完了したかどうかを確認できます。次回、それが完了したかどうかを確認したい場合、または、あなたがやることができない場合は、その上でgetを呼び出すことができます。

非同期IOは、実行するための呼び出しIOは、戻り値ではなくイベントを介して行われたことを通知します。

これは、ブロックまたは非ブロックになります。

非同期I/Oのブロック

Async IOをブロックするとは、IOを実行する呼び出しは通常のブロッキング呼び出しですが、呼び出したものはその呼び出しをスレッド内にラップすることです。 IOが完了するまでブロックし、その後、IOの結果の処理をコールバックに委任します。つまり、スレッドはまだ下にあります。 IOでブロックされているスタックですが、スレッドはそうではありません。

非ブロッキング非同期IO

これは実際にはより一般的なものであり、非ブロッキングIOは、標準の非ブロッキングIOのようにステータスをポーリングする必要がなく、代わりにコールバックを呼び出します非同期IOをブロックするのとは対照的に、これはスタックのどこでもブロックされるスレッドを持たないため、スレッドをブロックすることなく非同期動作が管理されるため、より速く、より少ないリソースを使用します。

CompletableFutureと考えることができます。プログラムには、マルチスレッドまたは非同期の非同期イベントフレームワークが必要です。そのため、コールバックは別のスレッドで実行されるか、現在のタスクが完了すると既存のスレッドで実行されるようにスケジュールされます。

区別をより徹底的に説明します こちら

3
Didier A.