2015-04-24 111 views
4

我被問到檢查計算時間取決於線程數正在處理該問題。因此我編寫了一個使用蒙特卡羅方法計算積分的程序。我正在劃分線程數的範圍。之後,我統計線程,計算他們的部分,最後總結部分結果以獲得一般結果。多線程增加計算時間 - Java

的問題是,時間計算與線程,而不是減少(i7處理器,Windows 7中)

幾個人做這個工作的人數增加了,我們不知道這是爲什麼。我希望有人會給我一個建議。 附上代碼:

import java.io.File; 
import java.io.FileWriter; 
import java.io.PrintWriter; 
import java.util.ArrayList; 
import java.util.concurrent.ConcurrentLinkedQueue; 


public class Runner { 

private static final int MAXT = 10; // maksymalna ilość wątków 
static PrintWriter outM; 
static PrintWriter outMTime; 

public static void main(String[] args){ 

    double xp = 2; 
    double xk = 3; 




    filesOp(); 

    // Wypisywanie kolumn tabeli 
    for(int threadNumber=1; threadNumber<=MAXT; threadNumber++){ 
      outM.print("\t"+ threadNumber); 
      outMTime.print("\t"+ threadNumber); 
     } 

    double time1; 
    double time2; 

    //double startTime=System.currentTimeMillis(); // Przed wystartowaniem programu 

    for(int n=10000; n<=10000000; n=n*10){ 

     System.out.println("Licze dla: " + n + " punktow."); 


      outM.print("\n"+n); 
      outMTime.print("\n"+n); 


     for(int threadNumber=1; threadNumber<=MAXT; threadNumber++){ 

      outM.print("\t"); 
      outMTime.print("\t"); 

      time1=System.nanoTime(); 
       multiThread(xp, xk, n, threadNumber); 
      time2=System.nanoTime(); 

      outMTime.print((time2-time1)/1000000); 
      // czas pracy dla danej liczby wątków 

     } 

    } 

    outM.close(); 
    outMTime.close(); 

} 


public static void multiThread(double xp, double xk, int n, int threadNumber){ 
    // Funkcja licząca całkę wielowątkowo. 
    // Całka do policzenia jest dzielona pomiędzy wątki 

    ArrayList<Thread> threadList = new ArrayList<Thread>(); 
    ConcurrentLinkedQueue<Double> results = new ConcurrentLinkedQueue<Double>(); 

    for(int i=0; i<threadNumber; i++){ 

     MonteCarlo mc = new MonteCarlo(xp+(i*((xk-xp)/threadNumber)), xp+((i+1)*((xk-xp)/threadNumber)), (int)(n/threadNumber), results); 


     Thread t = new Thread(mc); 
     threadList.add(t); 
     t.start(); 

    } 

    //for(int j=0; j<threadNumber; j++){ // pętla czeka na zakończenie wątków 
    for(Thread t : threadList){ 
     try { 
      //while(t.isAlive()){} 
      //threadList.get(j).join(); 
      t.join(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

    } 


    double wynik = 0; 
    //for(int k=0; k<results.size(); k++){ 
    for(double r: results){ 
     //wynik = wynik + results.remove(); 
     wynik= wynik + r; 
    } 


    outM.print(wynik); 
} 



public static void filesOp(){ 
    File fileTemp; 

    fileTemp = new File("wyniki.txt"); 
    if (fileTemp.exists()) fileTemp.delete(); 


    fileTemp = new File("pomiary.txt"); 
    if (fileTemp.exists()) fileTemp.delete(); 


    try { 

     outM = new PrintWriter(new FileWriter("wyniki.txt", true)); 
     outMTime = new PrintWriter(new FileWriter("pomiary.txt", true));  
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 


} 


public class MonteCarlo implements Runnable{ 

    double xp; 
    double xk; 
    long n; 
    ConcurrentLinkedQueue<Double> results; 

    MonteCarlo(double xp, double xk, long n, ConcurrentLinkedQueue<Double> results){ 
     this.xp=xp; 
     this.xk=xk; 
     this.n=n; 
     this.results=results; 
    } 

    //funkcja dla ktorej obliczamy calke 
    private static double func(double x) { 
     return x*x+3; 
    } 


    private static double funcIn(double x, double y) { 
     if ((y > 0) && (y <= func(x))) 
      return 1; 
     else if ((y > 0) && (y <= func(x))) 
      return -1; 
     return 0; 
    } 

    //random number from a to b 
    private static double randomPoint(double a, double b) { 
     return a + Math.random() * (b-a); 
    } 

    public void run(){  
     double yp, yk, calka; 
     int pointsIn; 


     yp = 0; 
     yk = Math.ceil(Math.max(func(xp), func(xk))); 

     pointsIn = 0; 

     for (long i=0; i<n; i++) { 
     pointsIn += funcIn(randomPoint(xp, xk), randomPoint(yp, yk)); 
     } 

     calka = (pointsIn/(double)n) * ((xk-xp) * (yk-yp));  

     results.add(calka); 

     } 


} 

和結果的例子:

10000 6.185818 2.821405 3.721287 3.470309 4.068365 3.604195 4.323075 4.192455 6.159694 4.239105

100000 10.994522 15.874134 34.992323 40.851124 36.199631 49.54579 45.122417 61.427132 55.845435 60.7661

百萬108.653008 274.443662 340.274574 407.054352 437.455361 469.853467 496.849012 584.519687 571.09329 594.152023

千萬1066.059033 2877.947652 3600.551966 4175.707089 4488.434247 5081.572093 5501.217804 6374.335759 6128.274553 6339.043475

+0

您不應該在計算中包含創建和啓動線程所花費的時間,他們需要花費大量時間來創建和啓動。另外,創建數千個對象也可能會歪曲您的統計信息。 – OldCurmudgeon

回答

5

問題很可能在於

private static double randomPoint(double a, double b) { 
    return a + Math.random() * (b-a); 
} 

Math.random()表現不佳在激烈的爭論中。如果您使用的是Java 7或更高版本,試試這個來代替:

private static double randomPoint(double a, double b) { 
    return ThreadLocalRandom.current().nextDouble(a, b); 
} 
+0

切換到'ThreadLocalRandom'使'randomPoint'的執行時間從151秒增加到203秒(在我的電腦上,java 8) – Aerus

+0

@Aerus嗯,在我的機器上解決了問題(Java 8)。 –

+0

同意。與[這裏]相同的問題(http://stackoverflow.com/questions/23663178/inefficient-threads-in-java) – apangin

0

使用靜態funtions經常是多線程的陷阱之一。 更爲一般的答案可以在this後發現。