如果我有2个CPU并为fork / join框架安排1000个任务,那么一次最多可以执行2个任务,还是在同一个CPU上并行执行更多任务? (比方说,也许有一个任务正在等待I / O,在这种情况下CPU将变为空闲而另一个线程可以运行)
答案 0 :(得分:5)
如果您自己不包含任何限制,则不会应用任何限制,Java将尽可能多地分叉线程(可能全部为1000,具体取决于系统限制)。这不太理想。如果你正在进行的计算可能有一些IO时间,但即使在大量的并发处理中也不会受到IO约束,你可能能够证明运行多一个线程,然后再运行可用的CPU数量。一次全部运行1000并不明智。
如果我有两个CPU并为fork / join框架安排1000个任务,那么一次最多可以执行2个任务,还是在同一个CPU上并行执行更多任务?< / p>
如果您有双核CPU,则一次只能实际执行2个线程。
答案 1 :(得分:3)
使用给定的目标并行度级构建ForkJoinPool; 默认情况下,等于可用处理器数量 。池尝试维护足够的活动(或可用)线程 动态添加,挂起或恢复内部工作线程, 即使某些任务停滞等待加入他人。但是,没有 面对被阻止的IO或其他,这种调整是有保证的 非托管同步。
所以它可能会在你的2个CPU上一次运行两个,如果CPU是超线程的话,可能一次运行四个(我不确定)。如果您对默认的并行级别不满意,可以通过调用以并行级别作为参数的ForkJoinPool构造函数来指定请求的并行级别。
答案 2 :(得分:1)
是否在cpu上启用了超线程?如果是这样,您可以同时运行2个以上的流程。
超线程的工作方式是复制处理器的某些部分 - 存储架构状态的部分 - 但不复制主要执行资源。这允许超线程处理器作为主机操作系统的两个“逻辑”处理器出现,允许操作系统同时调度两个线程或进程。
答案 3 :(得分:0)
我做了一个测试来验证这一点:
import java.util.concurrent.*;
public class Test {
private static class TestAction extends RecursiveAction {
private int i;
public TestAction(int i) {
this.i = i;
}
protected void compute() {
if (i == 0) {
invokeAll(new TestAction(1), new TestAction(2), new TestAction(3),
new TestAction(4), new TestAction(5), new TestAction(6));
return;
}
System.out.println(i + " start");
try { Thread.sleep(2000); } catch (Exception e) { }
System.out.println(i + " end");
}
}
public static void main(String[] args) {
new ForkJoinPool().invoke(new TestAction(0));
}
}
使用参考Oracle实现运行的结果是:
1 start
6 start <- wait 2 seconds
1 end
2 start
6 end
5 start <- wait 2 seconds
2 end
3 start
5 end
4 start <- wait 2 seconds
4 end
3 end
在Linux和Mac OS X上,相同的行为是一致的。
所以问题的答案是:是的,任务将在parallelism参数指定的CPU数量(或默认的总可用CPU)上执行。如果CPU时间可用且任务只是阻止等待某事,那么框架将不会自动执行任何其他任务。
由于我到目前为止看到的文档非常模糊,如果CPU是空闲的,框架应该做什么,这可能是一个实现细节。
答案 4 :(得分:0)
默认情况下,Fork / Join Framework会尝试将线程数保持等于核心数量(如果是单个核心机器,则创建一个线程)。您可以在makeCommonPool
类中的ForkJoinPool
方法中查看此代码。
如果您认为这会对您的CPU利用不足,则可以为parallelism
提供自定义值。
但最有趣的是,当当前线程占用IO上的CPU块时,有一种方法可以使ForkJoinPool创建更多线程。您所需要做的就是实现代码块,该代码块实际上阻塞了block
对象的ForkJoinPool.ManagedBlocker
方法实现中的IO,并将该ManagedBlocker
对象传递给{{1 } managedBlock
类的方法。完成此操作后,ForkJoinPool
将检查调用此方法的当前线程是否为ForkJoinPool
的实例。如果是,则ForkJoinPoolWorkerThread
通过创建可以接管CPU的新线程来补偿。
ForkjoinPool