0

Callable タスクのコレクションを受け取り、それらを並行して実行する単純なユーティリティを作成しています。所要時間の合計が、最長のタスクにかかる時間よりも少ないことを期待します。このユーティリティは、いくつかのエラー処理ロジックも追加します。いずれかのタスクが失敗し、その失敗が「再試行可能」として処理できるもの (タイムアウトやユーザー指定の例外など) である場合、タスクを直接実行します。

このユーティリティを ExecutorService に実装しました。次の 2 つの部分があります。

  1. submit() すべての Callable タスクを ExecutorService に送信し、Future オブジェクトを格納します。
  2. for ループで、各 Future の結果を get() します。例外が発生した場合は、「再試行可能な」ロジックを実行します。

このユーティリティを使用すると、タスクを順番に実行するよりも高速であることを確認するために、いくつかの単体テストを作成しました。テストごとに、特定の数の Callable を生成し、それぞれが基本的に Thread.sleep() を境界内のランダムな時間実行します。さまざまなタイムアウト、さまざまな数のタスクなどを試してみたところ、ユーティリティは順次実行よりも優れているように見えました。

しかし、この種のユーティリティを必要とする実際のシステムにそれを追加したところ、結果は非常に変わりやすいものでした。並列実行が高速な場合もあれば、低速な場合もあり、高速な場合もありましたが、それでも、最長の個人タスク.

私はそれをすべて間違っているだけですか?ExecutorService に invokeAll() があることは知っていますが、それは基になる例外を飲み込みます。また、CompletionService を使用して、完了した順序でタスクの結果をフェッチしようとしましたが、多かれ少なかれ同じ動作を示しました。私は今、ラッチとバリアについて調べています。これは、この問題を解決するための正しい方向ですか?

4

2 に答える 2

3

このユーティリティを使用すると、タスクを順番に実行するよりも高速であることを確認するために、いくつかの単体テストを作成しました。テストごとに、特定の数の Callable を生成し、それぞれが本質的に境界内のランダムな時間 Thread.sleep() を実行します

CPUもIOも使用していないため、これは確かに公正なテストではありません。並列スリープがシリアルよりも高速に実行されることを願っています:-)

しかし、この種のユーティリティを必要とする実際のシステムにそれを追加したところ、非常にばらつきのある結果が得られました

右。スレッド化されたアプリケーションがシリアル化されたアプリケーションよりも高速に実行されるかどうかは、多くの要因に大きく依存します。特に、IO バウンドのアプリケーションは、IO チャネルにバインドされているため、パフォーマンスが向上しませ。これにより、実際には同時操作を実行できません。アプリケーションが必要とする処理が多いほど、アプリケーションをマルチスレッドに変換するメリットが大きくなります。

私はそれをすべて間違っているだけですか?

詳細がないとわかりにくい。同時に実行されているスレッドの数をいじることを検討してください。処理するジョブが大量にある場合は、アーキテクチャの CPU の数に応じてを使用せずExecutos.newCachedThreadPool()、 を最適化する必要があります。newFixedSizeThreadPool(...)

また、IO 操作をいくつかのスレッドに分離し、処理を他のスレッドに分離できるかどうかを確認することもできます。ファイルから読み取る1つの入力スレッドと、データベースまたは何かに書き込む1つの出力スレッド(またはカップル)のように。したがって、複数のサイズのプールは、単一のスレッドプールを使用するよりも、さまざまなタイプのタスクに適している場合があります。

CompletionService を使用して、完了した順序でタスク結果を取得しようとしました

操作を再試行する場合は、 a を使用するのCompletionServiceがまさに正しい方法です。ジョブが終了して例外をスローする (または失敗を返す) と、ジョブを再開してすぐにスレッドプールに戻すことができます。これが原因でパフォーマンスの問題が発生する理由はわかりません。

于 2013-09-19T18:32:20.593 に答える