2016-04-06 16 views
2

私は、情報のためにリモートクライアントをポーリングし、その情報をリスト形式で返す呼び出し可能コードを書きました。私はthreadpoolexecutor forループを使い、Futureは複数のリモートクライアントに対して並列にタスクを実行しています。それから、私は将来のリストをすべてaddAll()と組み合わせ、巨大な結合リストを扱います。並行実行:未来対並行

私の質問は、parallelstream()を将来のループとforループを使うより効率的に使うことです。確かにコード化するのが簡単です!もし私がそのルートに行ったら、もうthreadpoolexecutorが必要でしょうか?

ありがとうございました!

 for(SiteInfo site : active_sites) { 
      TAG_SCANNER scanr = new TAG_SCANNER(site, loggr); 
      Future<List<TagInfo>> result = threadmaker.submit(scanr); 

      //SOUND THE ALARMS 
      try { 
       alarm_tags.addAll(result.get()); 
      } catch (InterruptedException | ExecutionException e) { 
       e.printStackTrace(); 
      } 
     } 

可能なコードは? Netbeansのは、一般parallelstream

active_sites.parallelstream().map((site) -> new TAG_SCANNER(site, loggr)).map((scanr) -> threadmaker.submit(scanr)).forEach((result) -> { 
      //SOUND THE ALARMS 
      try { 
       alarm_tags.addAll(result.get()); 
      } 
      catch (InterruptedException | ExecutionException e) { 
       e.printStackTrace(); 
      } 
     }); 
+0

いくつかのコードを投稿してください。 – sinu

+0

@sinuコードが掲載されています。 – TheFunk

+0

その実装では、あなたの現在の実装がシーケンシャルであるため、より速いでしょう。タスクをサブミットしてから、他のタスクを終了してすべてのタスクが終了するのを待つのではなく、現在のタスクが完了するのを待ってから次のタスクを実行します。だから、あなたは単一のスレッドですべてを行うことによって、より速くなるでしょう。 –

答えて

6

ここにはいくつかの誤解があります。まず、非同期タスクを使用してもリソースの使用率は向上しません。タスクをサブミットした直後にFuture.getを呼び出した場合は、次のタスクを実行する前にすぐに完了を待つ必要があります。

第2に、Netbeansによるコード変換ではほとんど同じコードが生成され、まだExecutorにタスクを提出しているため、並列ストリームでの提出(および待機)を行うだけで「未来対並列ストリーム」の問題ではありませんまだ実行プログラムを使用しています。あなたの最初のエラーのために、それを並行して実行するとスループットが向上するかもしれませんが、2つのミスを組み合わせて自分自身をキャンセルさせることは絶対にお勧めできません。ストリームAPIは、CPUバインドタスク用に最適化されており、CPUコアの数に一致する数のスレッドを作成し、待機中にこれらのスレッドがブロックされると新しいスレッドを生成しません。したがって、I/O操作を実行するために並列ストリームを使用するか、または一般に待機する可能性のある操作は、良い選択ではありません。また、実装で使用されるスレッドを制御することもできません。

ExecutorServiceは、リモートクライアントへの予想されるI/O帯域幅に応じて設定できます。しかし、提出直後にすべてのタスクを最初に提出し、その後すべてのタスクの完了を待つというエラーを修正する必要があります。あなたはそのためではなく、よりよい並列処理用のストリームAPIを使用することができますが、潜在的に読みやすさを向上:ここストリームAPIの使用はシーケンシャルのみにSiteInfoのリストを変換するためのものであることを

// first, submit all tasks, assuming "threadmaker" is an ExecutorService 
List<Future<List<TagInfo>>> futures=threadmaker.invokeAll(
    active_sites.stream() 
     .map(site -> new TAG_SCANNER(site, loggr)) 
     .collect(Collectors.toList()) 
); 
// now fetch all results 
for(Future<List<TagInfo>> result: futures) { 
    //SOUND THE ALARMS 
    try { 
     alarm_tags.addAll(result.get()); 
    } catch (InterruptedException | ExecutionException e) { 
     // not a recommended way of handling 
     // but I keep your code here for simplicity 
     e.printStackTrace(); 
    } 
} 

注意リストはCallable<List<TagInfo>>ですが、ループを使って同じことができます。

+0

ありがとうございます!私は、Futureの仕組みやストリームAPIの仕組みが理解できたと思います。あなたの答えは、私が少し難しかったことを明確にしています。 – TheFunk

2

は非常に効果的に並列処理を行うことは非常にスマートなプログラマによって書かれているこれらの線に沿って何かを示唆しています。それと

、あなたが主題の専門家でない限り、このような同時実行のパッケージなど、すべての他のJavaスレッドと同じように、その後、あなたはそれを自分で書く場合は、への可能性があります:

  • ラン遅くバグ
  • を紹介つまりは/ etcコード

に従うことが困難/より複雑なを持っている:はい、parallelstreamを使用しています。

+0

クール!これは物事を少しだけ読みやすくし、NetBeansは仕事のほとんどすべてを私のために変換しました。ありがとう! – TheFunk

+0

@ TheFunk:あまりにも急いではいけません。 [JB Nizetのコメント](http://stackoverflow.com/questions/36456032/concurrent-execution-future-vs-parallelstream/36458106#comment60526258_36456032)を本当に理解しましたか? – Holger

+0

@Holgerそう、そうだね。 ループを再開する前に結果を取得するのを待っているので、get()を呼び出すとforループが反復処理されません。私は、並列ストリーム後のすべてが同時に実行できるので、並列ストリームにはこの問題はないと思います。私は行方不明のものがありますか? – TheFunk