如何选择最佳线程数

时间:2011-07-03 00:45:52

标签: java multithreading

实际上我写了一个Java程序来计算Fibonacci系列中的特定数字。

现在的问题是我使用的核心数量是所需的线程数。但我观察到随着输入大小的增加,我通过增加线程数来获得更好的性能。

是否存在关于如何将问题划分为多个线程的现有公式/理论?

以下是源代码:

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Fibonacci {
    private static long[] value;

    public static void main(String args[]) throws InterruptedException {
        int n;
        try {
            n = Integer.parseInt(args[0]);
        } catch (Exception e) {
            throw new RuntimeException(
                    "Please enter in the form java n number ");
        }
        value = new long[n + 1];


        long start = System.nanoTime();
        int nThreads = Runtime.getRuntime().availableProcessors();
        ExecutorService executorService = Executors
                .newFixedThreadPool(nThreads);
        int result;
        try {
            result = fibonacciSum(n, executorService);
        } catch (ExecutionException e) {
            throw new RuntimeException("Thread Interuppted ");
        }
        System.out.print(" MultiThreading = " + result);
        long end = System.nanoTime();
        System.out.println("\t time = " + (end - start) + "ns");
    }


    private static class FibonacciThread implements Runnable {
        int index;
        int result;
        ExecutorService executorService;

        public FibonacciThread(int index) {
            this.index = index;
        }

        public void run() {
            try {
                this.result = fibonacciSum(index, executorService);
            } catch (Exception e) {
                throw new RuntimeException("Thread interupted");
            }
        }
    }

    private static int fibonacciSum(int index, ExecutorService executorService)
            throws InterruptedException, ExecutionException {
        if (index <= 2) {
            return 1;
        } else {

            FibonacciThread fibonacciThread1 = new FibonacciThread(index - 2);
            fibonacciThread1.executorService = executorService;
            Future future = executorService.submit(fibonacciThread1);
            Object object = future.get();
            int resultPart2 = fibonacciSum(index - 1, executorService);
            int result = fibonacciThread1.result + resultPart2;
            // executorService.shutdown();
            return result;
        }
    }

}

4 个答案:

答案 0 :(得分:5)

如果您还没有意识到这一点,Fibonacci数字不适合并行化。您将获得(越来越)更好的性能:

  • 使用单线程递归算法,
  • 使用带有 memoization
  • 的单线程递归算法
  • 通过解决递归关系并实现最终公式。

基本问题是天真的斐波那契计算需要指数的计算步骤。您不能通过多线程对其(在性能方面)产生影响,因为您拥有有限数量的处理器。

即使您拥有无限数量的处理器,线程设置/任务创建开销也超过了计算步骤的时间。

最后,使用执行程序服务和有界线程池进行Fibonacci时存在特殊问题。如果线程池太小(或N太大),则计算可能会卡住。例如,您对其进行编码的方式需要池中的~N个线程来计算fibonacci(N),即使大多数时间都会阻塞它们。 (理解这一点的最好方法是“手动执行”应用程序,注意每个时间点使用的线程数......以及它们正在做什么。)


因此,对于您的问题的简单答案是(对于此特定应用程序),您至少需要池中的N个线程来完成Fibonacci(N)的计算。 (这不是一般性答案。它是由您实施的算法细节强制实施的。)


使用线程计算斐波纳契数时还有很多其他的SO问题/答案。我建议你也阅读它们。

答案 1 :(得分:1)

我认为现有的公式没有创建多少线程。您必须查看I / O等因素。如果您的线程将在I / O调用上阻塞(速度慢很多),那么CPU可以在此期间运行另一个线程。另一方面,如果您的线程计算量很大,并且需要很少/不需要I / O,那么将线程数与内核数相匹配是一个好主意,因为您可以防止线程之间切换的开销。

答案 2 :(得分:0)

没有公式,因为它取决于您的问题,操作系统等。您将达到上下文切换的开销无助于您的原因的程度。如果每个任务都相同,则同一进程中的更多线程将仅表示上下文切换。

最好在这里尝试最佳方式。

答案 3 :(得分:0)

最佳线程数要考虑的一个重要因素是问题中的并行度。对于一次只能执行4个任务的问题,没有超过4个线程的点(甚至可能更慢)

如您所知,斐波那契系列的公式是

f(1) = 1
f(2) = 1
f(n) = f(n-1) + f(n-2)

唯一的并行度是针对低于3的值。对于大于此值的数字,在前一个值出现之前,无法计算每个值。这意味着最佳线程数是一个而且只有一个。

您可能会说,为什么可能会出现更多线程来提高性能。这可能是因为你采取了低效的策略,而且效率低下正在加速。

如果从一开始就采取最有效的策略,那么最佳线程数就是一个。