2015-04-24 68 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后发现。