web-dev-qa-db-ja.com

rxJavaスケジューラーの使用例

RxJavaには、 5つの異なるスケジューラー から選択できます:

  1. immediate():現在のスレッドですぐに作業を実行するスケジューラを作成して返します。

  2. trampoline():現在の作業が完了した後に実行される現在のスレッドで作業をキューするスケジューラーを作成して返します。

  3. newThread():作業単位ごとに新しいスレッドを作成するスケジューラを作成して返します。

  4. computation():計算作業用のスケジューラを作成して返します。これは、イベントループ、コールバックの処理、その他の計算作業に使用できます。このスケジューラでIOにバインドされた作業を実行しないでください。代わりに、Schedulers。io()を使用してください。

  5. io():IOにバインドされた作業用のスケジューラを作成して返します。実装は、必要に応じて大きくなるExecutorスレッドプールによってサポートされます。これは、非同期的にブロッキングIOを実行するために使用できます。このスケジューラで計算作業を実行しないでください。代わりに、Schedulers。computation()を使用してください。

質問:

最初の3つのスケジューラーは自明です。ただし、computationioについて少し混乱しています。

  1. 「IOバインド作業」とは正確には何ですか?ストリーム(Java.io)およびファイル(Java.nio.files)の処理に使用されていますか?データベースクエリに使用されていますか?ファイルのダウンロードまたはREST AP​​Iへのアクセスに使用されていますか?
  2. computation()newThread()とどう違いますか?すべてのcomputation()呼び出しは、毎回新しい(バックグラウンド)スレッドではなく、単一(バックグラウンド)スレッドで行われますか?
  3. IO作業を行うときに、computation()を呼び出すのが悪いのはなぜですか?
  4. 計算作業を行うときにio()を呼び出すのが悪いのはなぜですか?
234
bcorso

最も重要な点は、Schedulers.ioSchedulers.computationの両方が、質問で言及されている他のものとは対照的に、無制限のスレッドプールによって支えられていることです。この特性は、ExecutornewCachedThreadPoolで作成された場合(自動回収で無制限)にのみSchedulers.from(Executor)によって共有されます。スレッドプール)。

以前の回答およびウェブ上の複数の記事で豊富に説明されているように、Schedulers.ioおよびSchedulers.computationは、名前の作業タイプに最適化されているため、慎重に使用する必要があります。しかし、私の観点からすると、それらは最も重要な役割はリアクティブストリームに実際の同時実行性を提供することです

新規参入者の信念に反して、リアクティブストリームは本質的に同時ではなく、本質的に非同期でシーケンシャルです。このまさに理由で、Schedulers.ioは、I/O操作がブロックしているときにのみ使用されます(例:Apache IOUtilsなどのブロックコマンドを使用FileUtils.readFileAsString(...))したがって、操作が完了するまで呼び出しスレッドを凍結します。

Java AsynchronousFileChannel(...)などの非同期メソッドを使用しても、操作中に呼び出しスレッドがブロックされることはないため、別のスレッドを使用しても意味がありません。実際、Schedulers.ioスレッドは、イベントループを実行せず、コールバックが呼び出されないため、実際には非同期操作に適していません。

同じロジックが、データベースアクセスまたはリモートAPI呼び出しに適用されます。非同期またはリアクティブAPIを使用して呼び出しを行うことができる場合は、Schedulers.ioを使用しないでください。

並行性に戻ります。非同期または並行してI/O操作を行う非同期またはリアクティブAPIにアクセスできない場合があるため、唯一の代替手段は、別のスレッドで複数の呼び出しをディスパッチすることです。悲しいかな、リアクティブストリームは両端でシーケンシャルですが、良いニュースはflatMap()演算子は、コアで並行性を導入できます

並行性は、通常flatMap()演算子を使用して、ストリーム構造に構築する必要があります。この強力な演算子は、内部でマルチスレッドコンテキストをflatMap() embedded Function <T、R>に提供するように構成できます。そのコンテキストは、Scheduler.ioScheduler.computationなどのマルチスレッドスケジューラによって提供されます。

詳細については、RxJava2の記事をご覧ください。 Schedulers および Concurrency では、サンプルコードと、スケジューラを順次および同時に使用する方法についての詳細な説明があります。

お役に立てれば、

ソフトジェイク

2
softjake

このブログ投稿は優れた答えを提供します

ブログ投稿から:

Schedulers.io()は、無制限のスレッドプールによってサポートされています。これは、ファイルシステムとのやり取り、ネットワークコールの実行、データベースのやり取りなど、CPUを集中的に使用しないI/Oタイプの作業に使用されます。このスレッドプールは、ブロックIOの非同期実行に使用されます。

Schedulers.computation()は、利用可能なプロセッサの数までのサイズの境界付きスレッドプールによってサポートされます。画像のサイズ変更、大きなデータセットの処理など、計算またはCPU集中型の作業に使用されます。注意:利用可能なコアよりも多くの計算スレッドを割り当てると、スレッドが競合するため、コンテキストの切り替えとスレッド作成のオーバーヘッドによりパフォーマンスが低下しますプロセッサの時間。

Schedulers.newThread()は、スケジュールされた作業単位ごとに新しいスレッドを作成します。このスケジューラは、新しいスレッドが毎回生成され、再利用が発生しないため、高価です。

Schedulers.from(Executor executor)は、指定されたexecutorを基にしたカスタムスケジューラを作成して返します。スレッドプール内の同時スレッドの数を制限するには、Scheduler.from(Executors.newFixedThreadPool(n))を使用します。これにより、すべてのスレッドが占有されているときにタスクがスケジュールされると、キューに入れられます。プール内のスレッドは、明示的にシャットダウンされるまで存在します。

メインスレッドまたはAndroidSchedulers.mainThread()は、RxAndroid拡張ライブラリによってRxJavaに提供されます。メインスレッド(UIスレッドとも呼ばれます)は、ユーザーインタラクションが発生する場所です。このスレッドをオーバーロードしないように注意して、ジャンキーな非応答UIや、さらに悪いことに、アプリケーションが応答しません(ANR)ダイアログを防ぎます。

Schedulers.single()はRxJava 2の新機能です。このスケジューラは、要求された順序でタスクを順番に実行する単一のスレッドによってサポートされます。

Schedulers.trampoline()は、参加しているワーカースレッドの1つによってFIFO(先入れ先出し)の方法でタスクを実行します。これは、呼び出しスタックの増大を避けるために再帰を実装するときによく使用されます。

1
joe