2017-05-08 7 views
4

私はJava 8並列ストリームについて学んでいます。私は最初にExecutorを使ってコードを書いた後、並列ストリームを使っています。 Executorのアプローチ(5秒)と並行して2倍(10秒)の時間がかかるようです。私の意見では、パラレルストリームも同様のパフォーマンスを示す必要があります。なぜ並列ストリームは2倍の時間を要するか? 私のコンピュータは8つのコアを持っています。java 8並列ストリームにはさらに時間がかかります

/** 
* 
*/ 
package com.shashank.java8.parallel_stream; 

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Date; 
import java.util.List; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 

/** 
* @author pooja 
* 
*/ 
public class Sample { 

    public static int processUrl(String url) { 

     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     System.out.println("Running Thread " + Thread.currentThread()); 
     return url.length(); 
    } 

    /** 
    * @param args 
    * @throws Exception 
    */ 
    public static void main(String[] args) throws Exception { 
     usingExecutor(); 
     usingParallelStream(); 
    } 

    public static void usingParallelStream() { 

     Date start = new Date(); 
     // TODO Auto-generated method stub 
     int total = buildUrlsList().parallelStream().mapToInt(Sample::processUrl).reduce(0, Integer::sum); 
     Date end = new Date(); 
     System.out.println(total); 
     System.out.println((end.getTime() - start.getTime())/1000); 

    } 

    public static void usingExecutor() throws Exception { 
     Date start = new Date(); 
     ExecutorService executorService = Executors.newFixedThreadPool(100); 
     List<Future> futures = new ArrayList<>(); 

     for (String url : buildUrlsList()) { 
      futures.add(executorService.submit(() -> processUrl(url))); 

     } 

     // iterate through the future 
     int total = 0; 
     for (Future<Integer> future : futures) { 
      total += future.get(); 
     } 
     System.out.println(total); 
     Date end = new Date(); 
     System.out.println((end.getTime() - start.getTime())/1000); 

    } 

    public static List<String> buildUrlsList() { 
     return Arrays.asList("url1", "url2", "url3", "url4", "url5", "url6", "url7", "url8", "url9"); 

    } 

} 
+0

異なるプロセスに情報を移動する時間がボトルネックになる可能性があります。あなたはフランスの食べ物を手に入れるためにフランスまでずっと飛んでいってはいけません。データをコピーするのに多くの時間を費やし、実際の作業には時間がかかりません。 –

+1

さて、それはあなたのベンチマークとあなたのベンチマークについてです。ここを見てください:http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java。 – Eugene

+1

さらに、 'Sample :: processUrl'が何をしているのかわからないので、本当に助けにならないでしょう。しかし、8コアマシンで100スレッドの 'ExecutorSerivce'がまったくうまくいかないことは明らかです。 – Eugene

答えて

5

説明は非常に簡単です。あなたは8コアを持っているので、parallelStream()は通常8スレッドで作業を並列化するかもしれません。彼らはすべてすぐに仕事を取り、彼らはすべて5秒間眠る。そのうちの1人が次の(9番目の)タスクを受け取り、さらに5秒間スリープ状態になります。そして処理が終了する。これは〜5秒(8スレッド)+ 5秒(1スレッド)=合計10秒を意味します。しかし、実際にこれを見てみましょう。同じスレッドT [12]を2回タスクを完了し、5秒を終了することを

T[1] finished @[1494267500] 
T[12] finished @[1494267500] 
T[17] finished @[1494267500] 
T[13] finished @[1494267500] 
T[14] finished @[1494267500] 
T[16] finished @[1494267500] 
T[11] finished @[1494267500] 
T[15] finished @[1494267500] 
T[12] finished @[1494267505] 
36 
10 

注:のような出力を得ることができ、並列ストリームで

public static int processUrl(String url) { 

    try { 
     Thread.sleep(5000); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    System.out.println("T[" + Thread.currentThread().getId() + "] finished @[" + System.currentTimeMillis()/1000 + "]"); 
    return url.length(); 
} 

:私は少しあなたのコードを修正します8つのタスクの最初の 'ラウンド'後。

スレッドエグゼキュータでは、100スレッドを作成しました。だから、9つのスレッドは、一つのタスクそれぞれをつかむと、スレッドプールが枯渇されないため、実行時間は約5秒になります。

T[14] finished @[1494267783] 
T[11] finished @[1494267783] 
T[19] finished @[1494267783] 
T[17] finished @[1494267783] 
T[12] finished @[1494267783] 
T[16] finished @[1494267783] 
T[13] finished @[1494267783] 
T[15] finished @[1494267783] 
T[18] finished @[1494267783] 
36 
5 

注ここで同じ-S IDとは、スレッドがないこと。 (これはではありません固定プールのスレッドの普遍的な数を選択するためのお勧めです:-)私はあなたの実際の質問に精緻化しています)。

スケジューラを試して、ちょうど8スレッドの割り当て:スレッドプールが枯渇されますので、

ExecutorService executorService = Executors.newFixedThreadPool(8); 

が次に実行時間はほぼ同じである可能性が高いです。 URL-sが8ではなく9であれば同様のパフォーマンスに気付くでしょう。

OF COURSEこのコードが異なる環境で同じように動作するという保証はありません。

関連する問題