具有子任务的线程数



池中线程的优化是特定于具体情况的,尽管有一条经验法则说#threads=#CPU+1。然而,对于跨越其他线程并等待这些"子线程"(即,在thread.join((成功之前被阻止(的线程,这是如何工作的呢?

假设我有代码需要执行任务列表(2(,其中有子任务(2(、子任务(3(等等。任务总数为2*2*3=12,但将创建18个线程(因为线程将"生成"更多的子任务(线程(,其中生成更多线程的线程将被阻止,直到一切结束。请参阅下面的伪代码。

我假设,对于一个有N个核的CPU,有一条经验法则,如果活动线程的最高数量(12(是#CPU+1,那么一切都可以并行化。这是正确的吗?

伪代码

outputOfTask = []
for subtask in SubTaskList
outputOfTask --> append(subtask.doCompute())
// wait untill all output is finished.

在子任务.java中:例如,每个子任务实现相同的接口,但可能不同。

outputOfSubtask = []
for task in subsubTaskList
// do some magic depending on the type of subtask
outputOfSubtask -> append( task.doCompute())
return outputOfSubtask

在sububtask.java中:

outputOfSubsubtask = []
for task in subsubsubtask
// do some magic depending on the type of subsubtask
outputOfSubsubtask -> append( task.doCompute())
return outputOfSubsubtask

编辑:伪代码Java代码。我在最初的问题中使用了这个来检查有多少线程处于活动状态,但我认为伪代码更清楚。请注意:我使用了Eclipse Collection,它引入了asParallel函数,该函数允许对代码进行较短的表示。

@Test
public void testasParallelthreads() {
// // ExecutorService executor = Executors.newWorkStealingPool();
ExecutorService executor = Executors.newCachedThreadPool();
MutableList<Double> myMainTask = Lists.mutable.with(1.0, 2.0);
MutableList<Double> mySubTask = Lists.mutable.with(1.0, 2.0);
MutableList<Double> mySubSubTask = Lists.mutable.with(1.0, 2.0);
MutableList<Double> mySubSubSubTask = Lists.mutable.with(1.0, 2.0, 2.0);
MutableList<Double> a = myMainTask.asParallel(executor, 1)
.flatCollect(task -> mySubTask.asParallel(executor,1)
.flatCollect(subTask -> mySubSubTask.asParallel(executor, 1)
.flatCollect(subsubTask   -> mySubSubSubTask.asParallel(executor, 1)
.flatCollect(subsubTask -> dummyFunction(task, subTask, subsubTask, subsubTask,executor))
.toList()).toList()).toList()).toList();        
System.out.println("pool size: " + ((ThreadPoolExecutor) executor).getPoolSize());
executor.shutdownNow();
}
private MutableList<Double> dummyFunction(double a, double b, double c, double d, ExecutorService ex) {
System.out.println("ThreadId: " + Thread.currentThread().getId());
System.out.println("Active threads size: " + ((ThreadPoolExecutor) ex).getActiveCount());
return Lists.mutable.with(a,b,c,d);
}

我假设,对于一个有N个核的CPU,有一条经验法则,如果活动线程的最高数量(12(是#CPU+1,那么一切都可以并行化。这是正确的吗?

这个话题很难概括。即使使用实际代码,应用程序的性能也很难确定。即使您可以得出一个估计,实际性能在不同的运行之间可能会有很大的差异——尤其是考虑到线程之间正在相互作用。如果提交到线程池中的作业是独立的并且完全绑定CPU,那么我们唯一可以使用#CPU + 1编号。

我建议在模拟负载下尝试许多不同的线程池大小值,以找到适合您的应用程序的最佳值。检查总体吞吐量数字或系统负载统计数据应该会为您提供所需的反馈。

然而,对于跨越其他线程并等待(即阻塞,直到thread.join((成功(这些"子线程"的线程,这是如何工作的?

线程将阻塞,如果可能的话,由os/jvm调度另一个线程。如果您有一个线程池执行器,并从其中一个任务调用join,那么另一个任务甚至不会启动。对于使用更多线程的执行器,那么阻塞任务将阻塞单个线程,os/jvm可以自由调度其他线程。

这些被阻塞的线程不应该消耗CPU时间,因为它们被阻塞了。所以我假设,对于一个有N个核的CPU,有一条经验法则,如果活动线程的最高数量(24(是#CPU+1,那么一切都可以并行化。这是正确的吗?

活动线程可能会被阻塞。我认为你在这里混合了#CPU、内核数量和虚拟内核数量。如果你有N个物理核心,那么你可以并行运行N个cpu绑定的任务。当你有其他类型的阻塞或寿命很短的任务时,你可以有更多的并行任务。

最新更新