实际上我写了一个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;
}
}
}
答案 0 :(得分:5)
如果您还没有意识到这一点,Fibonacci数字不适合并行化。您将获得(越来越)更好的性能:
基本问题是天真的斐波那契计算需要指数的计算步骤。您不能通过多线程对其(在性能方面)产生影响,因为您拥有有限数量的处理器。
即使您拥有无限数量的处理器,线程设置/任务创建开销也超过了计算步骤的时间。
最后,使用执行程序服务和有界线程池进行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的值。对于大于此值的数字,在前一个值出现之前,无法计算每个值。这意味着最佳线程数是一个而且只有一个。
您可能会说,为什么可能会出现更多线程来提高性能。这可能是因为你采取了低效的策略,而且效率低下正在加速。
如果从一开始就采取最有效的策略,那么最佳线程数就是一个。