2015-01-14 1 views
2

다중 스레드를 사용하는 방법을 이해하려고합니다. 나는 i의 값을 증가시키는 간단한 프로그램을 작성했다. 두 개의 방법을 사용하여 400,000 번 : 단일 스레드 방식 (0에서 400,000)과 다중 스레드 방식 (제 경우에는 4 번 : 0에서 100,000까지)을 숫자와 함께 사용한다. 스레드의 Runtime.getRuntime().availableProcessors()와 같습니다.java - 단일 스레드보다 다중 스레드에서 간단한 계산이 더 걸림

내가 측정 한 결과에 놀랐습니다. 단일 스레드 방식은 확실히 빨라졌으며 때로는 3 배 빨랐습니다.

Computation time using 4 threads : 10ms. Computation time using main thread : 3ms.

사람이 설명 할 수 없습니다 :

public class Main { 
    public static int LOOPS = 100000; 
    private static ExecutorService executor=null; 

    public static void main(String[] args) throws InterruptedException, ExecutionException { 

     int procNb = Runtime.getRuntime().availableProcessors(); 
     long startTime; 
     long endTime; 

     executor = Executors.newFixedThreadPool(procNb); 
     ArrayList<Calculation> c = new ArrayList<Calculation>(); 

     for (int i=0;i<procNb;i++){ 
      c.add(new Calculation()); 
     } 

     // Make parallel computations (4 in my case) 
     startTime = System.currentTimeMillis(); 
     queryAll(c); 
     endTime = System.currentTimeMillis(); 

     System.out.println("Computation time using " + procNb + " threads : " + (endTime - startTime) + "ms"); 

     startTime = System.currentTimeMillis(); 
     for (int i =0;i<procNb*LOOPS;i++) 
     { 

     } 
     endTime = System.currentTimeMillis(); 
     System.out.println("Computation time using main thread : " + (endTime - startTime) + "ms"); 
    } 

    public static List<Integer> queryAll(List<Calculation> queries) throws InterruptedException, ExecutionException { 
     List<Future<Integer>> futures = executor.invokeAll(queries); 
     List<Integer> aggregatedResults = new ArrayList<Integer>(); 
     for (Future<Integer> future : futures) { 
      aggregatedResults.add(future.get()); 
     } 
     return aggregatedResults; 
    } 

} 

class Calculation implements Callable<Integer> { 

    @Override 
    public Integer call() { 
     int i; 
     for (i=0;i<Main.LOOPS;i++){ 
     } 
     return i; 
    } 
} 

콘솔 : 여기 내 코드는?

+0

당신이 멀티 스레드에서 너무 많은 일을 생각하지 않는다? 미래를 창조하고, 미래를리스트에 추가합니까? 또한 다중 스레드는 항상 단일 스레드보다 좋을 것이라는 필수 사항은 아닙니다. – SMA

+0

여러 스레드를 만드는 것이 값을 늘리는 것보다 오래 걸리는 것 같습니다. – peterremec

+1

물론 멀티 스레딩에는 오버 헤드가 있습니다. 멀티 스레딩 이점을 얻을만큼 큰 문제가 필요합니다. 또한 플랫폼, 하드웨어 (멀티 코어) 및 구현 (Java8 스트림은 멀티 코어를 많이 사용할 수 있음)에 따라 다릅니다. – PeterMmm

답변

8

추가 작업은 1 cpu주기가 걸리므로 CPU가 3GHz로 실행되는 경우 0.3 나노초입니다. 400k 번 수행하면 120k 나노초 또는 0.1 밀리 초가됩니다. 따라서 측정을 시도하는 작업보다 스레드 시작, 스레드 전환, JIT 컴파일 등의 오버 헤드에 더 큰 영향을받습니다.

또한 컴파일러 최적화를 고려해야합니다. 빈 루프를 메서드에 넣고이 메서드를 여러 번 실행하면 시간이 지나면 0ms에서 실행된다는 것을 알 수 있습니다. 왜냐하면 컴파일러는 루프가 아무 것도하지 않고 완벽하게 최적화한다고 판단하기 때문입니다.

jmh과 같은 마이크로 벤치마킹 용 특수 라이브러리를 사용하는 것이 좋습니다.

은 참조 : How do I write a correct micro-benchmark in Java?

+0

답변 해 주셔서 감사합니다. 루프 수를 10 배로 늘린 경우에도 결과는 동일합니다. 내 "for"루프가 비어 있다는 것을 강조하는 것이 정말로 중요하다고 생각합니다. 컴파일러는 계산을 최적화합니다 ... 그리고 내 벤치 마크는 편향되었습니다! – ThomasM

관련 문제