为什么单线程操作g所花的时间比没有线程的时间长3倍?

时间:2019-10-14 23:35:28

标签: java multithreading time cpu

我正在测试Java的并发性,我的目标是确定拥有多个线程是否真正有益,但是,我得到的结果并没有加总。我正在尝试优化阶乘函数,对于此特定测试,我正在使用1e9!我想要模1e9 + 7的结果,以免溢出。首先,我根据number_of_threads划分数字,并分别为每个线程分配其工作。然后,我通常会这样做并比较我得到的时间。看来,当number_of_threads = 4时,与没有线程的版本相比,我得到的结果更好,这是有道理的,因为我的CPU有4个内核。正如预期的那样,任何大于4的线程都比仅4的线程具有更慢的时间。但是,当少于4个线程时,结果变得很大,例如,只有1个线程,我希望它的持续时间与做相同它没有线程+开销。没有线程,我只有1个线程,而我得到6.2秒和19.3,这与开销无关,相差太大。

要测试为什么,我在run方法上放置了一个计数器,有时,似乎其中for的仅1个周期的执行花费了超过一毫秒的时间,而这不应该执行,因为它只是两个操作加上计时器。

public class Calc implements Runnable{
    long min, max, mod, res;
    Res r;
    public Calc(long min, long max, long mod, Res r) {
        this.min = min;
        this.max = max;
        this.mod = mod;
        res = 1;
        this.r = r;
    }
    public void run() {
        for(long i = min; i <= max; i++) {
            res *= i;
            res %= mod;
        }
        r.addup(res);
    }
}

public class Res{
    long result;
    long mod;
    public Res(long mod) {
        result = 1;
        this.mod = mod;
    }
    public synchronized void addup(long add) {
        result *= add;
        result %= mod;
    }
    public long getResult() {
        return result;
    }
}

public class Main{
    public static void main(String args[]) {
        long startTime = System.nanoTime();
        final long factorial = 1000000000L;
        final long modulo = 1000000007L;
        Res res = new Res(modulo);
        int number_of_threads = 1;
        Thread[] c = new Thread[number_of_threads];
        long min = 1, max = factorial/(long)number_of_threads;
        long cant = max;
        for(int i = 0; i < number_of_threads; i++) {
            if((long)i < (factorial % number_of_threads))max++;
            c[i] = new Thread(new Calc(min, max, modulo, res));
            c[i].start();
            min = max +1;
            max += cant;
        }
        for(int i = 0; i < number_of_threads; i++) {
            try {
                c[i].join();
            }catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println(res.getResult());
        long endTime   = System.nanoTime();
        long totalTime = endTime - startTime;
        System.out.println((double)totalTime/1000000000L);
    }
}

当number_of_threads = 1时,我得到19.3秒。当number_of_threads = 2时,我得到10.1秒。当number_of_threads = 3时,我得到7.1秒。当number_of_threads = 4时,我得到5.4秒。在没有线程的情况下,我得到6.2秒(我用相同的方法计算出这个时间)

只有1个线程和没有线程之间应该没有太大的区别,对于2和3个线程,它应该比没有线程快。为什么会这样,有什么办法可以解决?谢谢。

编辑:添加时没有线程版本

public class Main{
    public static void main(String args[]) {
        long startTime = System.nanoTime();
        final long factorial = 1000000000L;
        final long modulo = 1000000007L;

        long res = 1;
        for(long i = 1; i <= factorial; i++) {
            res *= i;
            res %= modulo;
        }
        System.out.println(res);
        long endTime   = System.nanoTime();
        long totalTime = endTime - startTime;
        System.out.println((double)totalTime/1000000000L);
    }

}

1 个答案:

答案 0 :(得分:0)

之所以会发生这种情况,是因为您的“无线程”(仅主线程)版本使用所有易于优化的编译时间常数。

如果您确定编译器不会提前知道值是什么:

class Main{
    public static void main(String args[]) {
        long factorial = Long.parseLong(args[0]);
        long modulo = Long.parseLong(args[1]);
        long startTime = System.nanoTime();

        long res = 1;
        for(long i = 1; i <= factorial; i++) {
            res *= i;
            res %= modulo;
        }
        System.out.println(res);
        long endTime   = System.nanoTime();
        long totalTime = endTime - startTime;
        System.out.println((double)totalTime/1000000000L);
    }

}

然后它会明显变慢:

$ java Main 1000000000 1000000007
698611116
11.368487148

在我的机器上,甚至比其他机器的1线程情况还多:

$ java Main
698611116
10.709532315

类似地,如果您修改1线程示例以使用.run()而不是.start(),则所有内容都将在主线程上运行,但是在1线程的情况下将不会加速。 / p>