2017-05-08 3 views
4

나는 자바 8 병렬 스트림에 대해 배우려고합니다. 먼저 Executor를 사용하고 병렬 스트림을 사용하여 코드 아래에 작성했습니다. Executor 접근 (5 초)만큼 병렬 스트림이 두 번 (10 초) 소요됩니다. 제 생각에는 병렬 스트림도 비슷한 성능을 보여야합니다. 병렬 스트림이 두 배의 시간이 걸리는 이유는 무엇입니까? 내 컴퓨터에는 8 개의 코어가 있습니다.자바 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 초 동안 잠을 자게됩니다. 그런 다음 그들 중 하나가 다음 (9 일) 작업을 수행하고 5 초 더 자게됩니다. 그런 다음 처리가 완료됩니다. 이것은 ~ 5 초 (8 스레드) + 5 초 (1 스레드) = 총 10 초를 의미합니다. 그러나 이것을 실제로 보자. 같은 스레드 T는 [12]를 두 번 작업을 완료하고 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 

주를 같은 아무 스레드가 없음을 여기에 ID-S. (이것은 입니다. 고정 풀에 대한 일반적인 스레드 수를 선택하는 것이 좋습니다 .-) 나는 실제 질문에 대해 자세히 설명하고 있습니다.) 스케줄러와

실험과는 8 스레드를 할당합니다

ExecutorService executorService = Executors.newFixedThreadPool(8); 

그런 다음 실행 시간이 스레드 풀이 고갈되기 때문에 거의 동일 할 것으로 예상된다. URL이 8이 아니라 9 일 경우 유사한 성능을 보입니다.

물론이 코드가 서로 다른 환경에서 동일하게 작동한다는 보장은 없습니다.

관련 문제