Java ExecutorService 解决递归斐波那契数列

发布于 2024-11-18 04:16:13 字数 2007 浏览 4 评论 0原文

我需要使用线程递归地根据斐波那契数列中的某些索引找出数字,我尝试了以下代码,但程序永远不会结束。如果我遗漏了什么,请告诉我。

代码

  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

我不是从调用方法中调用 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);
  }
}

I need to find out the number based on some index in the Fibonacci Series recursively using threads and I tried the following code, but the program never ends. Please let me know if I am missing something.

Code:

  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));
    }
  }

Fixed it (Thanks to fiver)

Instead of calling getNumber(int) from the call method, I am calling to a dynamic programming algorithm that computes the number at that index.

The code for that is:

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);
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

抚笙 2024-11-25 04:16:13

这种递归会很快使堆栈溢出。这是因为您一遍又一遍地计算较低的斐波那契数 - 指数级的多次。

避免这种情况的一种有效方法是使用记忆递归(一种动态编程方法)

基本上使用静态数组来保存已经计算出的斐波那契数,并且每当需要时,从数组中取出它(如果已经计算过)。如果不是,则计算它并将其存储在数组中。这样每个数字只会被计算一次。

(当然可以使用其他数据结构代替数组,即hashtable)

This recursion will overflow the stack very fast. This is because you are computing lower fibonacci numbers over and over again - exponentially many number of times.

One effective way to avoid that is to use memoized recursion (a dynamic programming approach)

Basically use a static array to hold the already computed fibonacci numbers and whenever you need one, take it from the array, if it's already computed. If not, then compute it and store it in the array. This way each number will be computed only once.

(You can use other data structure instead of array, of course, i.e. hashtable)

可爱咩 2024-11-25 04:16:13

您正在做的是将简单递归替换为通过线程/任务的递归。

在遇到 fib(0) 和 fib(1) 情况之前,每个任务都会再提交两个任务,然后等待它们完成。当它等待时,它仍在使用线程。由于线程池是有限的,您很快就会遇到对 submit 的调用阻塞......并且整个计算被锁定。


除此之外,indexMinusTwo 中存在一个错误,这会导致计算给出错误的答案。


但是递归多线程过程仍然比记忆的递归非多线程过程花费更长的时间..有什么提高性能的技巧吗?

即使假设您“修复”了上述问题(例如,通过使用无界线程池),您也不可能能够实现斐波那契的多线程版本,其性能优于单线程版本。 - 使用记忆的线程版本。该计算根本不适合并行化。

What you are doing is replacing simple recursion with recursion via threads / tasks.

Until you get to the fib(0) and fib(1) cases, each task submits two more tasks, and then waits for them to complete. While it is waiting, it is still using a thread. Since the thread pool is bounded, you soon get to the point where calls to submit block ... and the whole computation locks up.


In addition to that, you've got a bug in indexMinusTwo which would result in the computation giving the wrong answer.


But still the recursive multithreaded procedure takes much longer than the memoized recursive non-multithreaded one.. any tip to improve performance?

Even assuming that you "fixed" the above problem (e.g. by using an unbounded thread pool) there is no way that you will be able to do a multi-threaded version of fibonacci that performs better than a single-threaded version that uses memoization. The computation is simply not suited to parallelization.

孤檠 2024-11-25 04:16:13

当您有独立的任务需要执行时,线程效果最佳。根据定义,斐波那契数列没有任何并行度。每个 f(n) 取决于前两个值。因此,使用多个线程不可能比使用一个线程更快地计算 f(n) (除非您有一个低效的算法),

但是,您唯一可以并行处理大数的可能是 + 操作这可能 a) 复杂 b) 很难比单线程解决方案更快。

计算斐波那契数的最快/最简单的方法是在一个线程中使用循环。您不需要使用递归或记住值。

Threads work best when you have independant tasks to perform. The fibonacci series by definition does not have any degrees of parallelism. Each f(n) depends on the previous two values. As such it is not possible to calculate f(n) faster using multiple threads than using one (unless you have an inefficient algo)

The only thing you could make parallel potentially the + operation for large numbers, however this is likely to be a) complex b) difficult to make faster than the single threaded solution.

The fastest/simplest way to calculate fibonacci numbers is to use a loop in one thread. You don't need to use recusrion or memorize values.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文