我正在尝试 Java 中的 executor 服务,并编写了以下代码来运行 Fibonacci(是的,大规模递归版本,只是为了强调 executor 服务)。
令人惊讶的是,如果我将 nThreads 设置为 1,它会运行得更快。这可能与提交给执行器服务的每个“任务”的大小非常小有关。但如果我将 nThreads 设置为 1,它仍然必须是相同的数字。
为了查看对共享原子变量的访问是否会导致此问题,我用注释“查看文本”注释掉了这三行,并查看了系统监视器以查看执行需要多长时间。但结果是一样的。
知道为什么会这样吗?
顺便说一句,我想将它与 Fork/Join 的类似实现进行比较。事实证明它比 F/J 实现要慢得多。
public class MainSimpler {
static int N=35;
static AtomicInteger result = new AtomicInteger(0), pendingTasks = new AtomicInteger(1);
static ExecutorService executor;
public static void main(String[] args) {
int nThreads=2;
System.out.println("Number of threads = "+nThreads);
executor = Executors.newFixedThreadPool(nThreads);
Executable.inQueue = new AtomicInteger(nThreads);
long before = System.currentTimeMillis();
System.out.println("Fibonacci "+N+" is ... ");
executor.submit(new FibSimpler(N));
waitToFinish();
System.out.println(result.get());
long after = System.currentTimeMillis();
System.out.println("Duration: " + (after - before) + " milliseconds\n");
}
private static void waitToFinish() {
while (0 < pendingTasks.get()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
executor.shutdown();
}
}
class FibSimpler implements Runnable {
int N;
FibSimpler (int n) { N=n; }
@Override
public void run() {
compute();
MainSimpler.pendingTasks.decrementAndGet(); // see text
}
void compute() {
int n = N;
if (n <= 1) {
MainSimpler.result.addAndGet(n); // see text
return;
}
MainSimpler.executor.submit(new FibSimpler(n-1));
MainSimpler.pendingTasks.incrementAndGet(); // see text
N = n-2;
compute(); // similar to the F/J counterpart
}
}
运行时间(大约):
- 1 个线程:11 秒
- 2 个线程:19 秒
- 4 个线程:19 秒
更新:我注意到即使我在执行器服务中使用一个线程,整个程序也会使用我机器的所有四个内核(每个内核平均使用率约为 80%)。这可以解释为什么在 executor 服务中使用更多线程会减慢整个进程,但是现在,如果 executor 服务中只有一个线程处于活动状态,为什么这个程序使用 4 个内核?