我需要使用线程以递归方式找出Fibonacci系列中某些索引的数字,我尝试了以下代码,但程序永远不会结束。如果我遗失了什么,请告诉我。
代码:
import java.math.BigInteger;
import java.util.concurrent.*;
public class MultiThreadedFib {
private ExecutorService executorService;
public MultiThreadedFib(final int numberOfThreads) {
executorService = Executors.newFixedThreadPool(numberOfThreads);
}
public BigInteger getFibNumberAtIndex(final int index)
throws InterruptedException, ExecutionException {
Future<BigInteger> indexMinusOne = executorService.submit(
new Callable<BigInteger>() {
public BigInteger call()
throws InterruptedException, ExecutionException {
return getNumber(index - 1);
}
});
Future<BigInteger> indexMinusTwo = executorService.submit(
new Callable<BigInteger>() {
public BigInteger call()
throws InterruptedException, ExecutionException {
return getNumber(index - 2);
}
});
return indexMinusOne.get().add(indexMinusTwo.get());
}
public BigInteger getNumber(final int index)
throws InterruptedException, ExecutionException {
if (index == 0 || index == 1)
return BigInteger.valueOf(index);
return getFibNumberAtIndex(index - 1).add(getFibNumberAtIndex(index - 2));
}
}
修正了(感谢 fiver )
我没有从call方法中调用getNumber(int),而是调用一个动态编程算法来计算该索引处的数字。
代码是:
public class DynamicFib implements IFib {
private Map<Integer, BigInteger> memoize = new HashMap<Integer, BigInteger>();
public DynamicFib() {
memoize.put(0, BigInteger.ZERO);
memoize.put(1, BigInteger.ONE);
}
public BigInteger getFibNumberAtIndex(final int index) {
if (!memoize.containsKey(index))
memoize.put(index, getFibNumberAtIndex(index - 1).add(getFibNumberAtIndex(index - 2)));
return memoize.get(index);
}
}
答案 0 :(得分:1)
这种递归会非常快地溢出堆栈。这是因为你反复计算较低的斐波那契数 - 指数多次。
避免这种情况的一种有效方法是使用memoized recursion(动态编程方法)
基本上使用静态数组来保存已经计算过的斐波纳契数,无论何时需要,都可以从数组中取出,如果已经计算过的话。如果没有,则计算并将其存储在数组中。这样每个数字只会计算一次。
(您可以使用其他数据结构而不是数组,当然,也就是哈希表)
答案 1 :(得分:1)
您正在做的是通过线程/任务使用递归替换简单递归。
在你看到fib(0)和fib(1)的情况之前,每个任务都会再提交两个任务,然后等待它们完成。在等待时,它仍在使用线程。由于线程池是有界的,你很快就会调用submit
来阻止...并且整个计算都会锁定。
除此之外,你在indexMinusTwo
中遇到了一个错误,导致计算错误答案。
但是,递归多线程程序还需要比memoized递归非多线程程序更长的时间。任何提高性能的技巧?
即使假设您“修复”了上述问题(例如,通过使用无界线程池),无法您将能够执行更好性能的多线程斐波那契版本而不是使用memoization的单线程版本。计算根本不适合并行化。
答案 2 :(得分:0)
当您执行独立任务时,线程最有效。根据定义,斐波那契系列没有任何程度的并行性。每个f(n)取决于前两个值。因此,使用多个线程比使用多个线程更快地计算f(n)(除非你的算法效率低)
对于大数字,你唯一可以并行的+
操作是平行的,但这可能是a)复杂的b)难以比单线程解决方案更快。
计算斐波纳契数的最快/最简单的方法是在一个线程中使用循环。您不需要使用recusrion或记忆值。