java – 并行化比非并行化任务花费更长的时间

我需要为大学做一个编程任务.任务是实现一个程序,返回方程q²3qpp²=r²(q,p,r素数)的所有解.随后,程序将通过并行化加速.

不幸的是我们必须使用BigInteger,所以不要感到惊讶.

这是我写的课程,它准确计算了这个等式.

    public boolean calculateEquation() {
    //Equation: p² + 3pq + q² = r²
    if (calculatePSquare().add(calculate3TimesPQ()).add(calculateQSquare()).equals(calculateRSquare())) {
        System.out.println("p: " + p + " q: " + q + " r: " + r);
    }
    return calculatePSquare().add(calculate3TimesPQ()).add(calculateQSquare()).equals(calculateRSquare());
}
@Override
public void run() {
    calculateEquation();
}

该类的完整代码:
https://pastebin.com/wwrDurUT

我的下一步是测试代码并停止时间以查看并行化是否稍后工作.为了实现并行化,我查看了不同的主题,其中包括链接的主题:What is the easiest way to parallelize a task in java?

这是我的结果:

ExecutorService executorService = Executors.newFixedThreadPool(Configuration.instance.maximumNumberOfCores);
        ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(executorService);

        for (BigInteger pValue : possiblePValues) {
            for (BigInteger qValue : possibleQValues) {
                for (BigInteger rValue : possibleRValues) {
                    executorCompletionService.submit(new Thirteen(pValue, qValue, rValue), null);
                }
            }
        }
        executorCompletionService.take();

完整代码:
https://pastebin.com/kviEnnFH

现在有趣的是,如果任务数量很少,并行化版本只会更快.对于0-500之间的所有素数,并行化版本更快.如果我取0到2000之间的所有素数,结果看起来非常不同:

所有素数在0到100之间:

没有并行化:
任务花了:110ms

并行:
任务花了:64ms

0到2000之间的所有素数:

没有并行化:
任务花了:7797ms

并行:
任务花了:25799ms

由于关于这个主题的资源很少有易于理解,而且我真的不太明白我的代码究竟是什么,我很惊讶为什么它的行为如此.

最佳答案 首先,使用三重嵌入式for循环实现这个p²3pqq²=r²方程是没有意义的,这导致具有O(n)= n ^ 3的复杂度.这可以仅使用两个for循环来完成,因为如果我们知道p和q的值,则可以使用等式计算r.

for (BigInteger p: possiblePValues) {
    for (BigInteger q: possibleQValues) {
        BigInteger r = p.pow(2).add(q.pow(2)).add(p.multiply(q).multiply(new BigInteger("3")))
        // decide if sqrt(r) is prime
     }
 }

现在,如果我们已经在Hashmap中保存了预先计算的素数,我们可以通过查找立即确定r是否为素数.

关于parallalization:
您的方法是错误的,因为您只是为某些操作生成线程,这些操作需要相对较短的时间才能完成.可能线程管理的开销比计算方程本身的操作花费的时间更长.我猜这就是为什么你的多线程版本运行时间更长的原因.
关于如何并行化两个嵌入式for循环没有黄金法则.我的方法是将第一个循环分成较小的块,具体取决于你拥有多少个核心并创建一些间隔.例如,如果我们有100个素数和4个线程,第一个线程将采用索引从0到24的p值,第二个线程从25到49,依此类推.第二个for循环应该在每个线程中从0到100运行.使用此方法,您可以计算所有可能的r值.

点赞