【问题标题】:How do I know if Fork and Join has enough pool size in Java?我如何知道 Fork 和 Join 在 Java 中是否有足够的池大小?
【发布时间】:2018-01-08 20:28:46
【问题描述】:

我正在尝试对一些大数据实施分而治之的解决方案。我使用 fork 和 join 将事物分解为线程。但是我有一个关于分叉机制的问题:如果我将分而治之的条件设置为:

@Override
protected SomeClass compute(){
    if (list.size()<LIMIT){
        //Do something here
        ...
    }else{
        //Divide the list and invoke sub-threads
        SomeRecursiveTaskClass subWorker1 = new SomeRecursiveTaskClass(list.subList());
        SomeRecursiveTaskClass subWorker2 = new SomeRecursiveTaskClass(list.subList());
        invokeAll(subWorker1, subWorker2);
        ...
    }
}

如果没有足够的资源调用subWorker 会发生什么(例如,池中没有足够的线程)? Fork/Join 框架是否为可用线程维护池大小?还是应该将此条件添加到我的分治逻辑中?

【问题讨论】:

    标签: java multithreading fork-join forkjoinpool


    【解决方案1】:

    每个ForkJoinPool 都有一个配置的目标parallelism。这与线程数不完全匹配,即如果工作线程将通过ManagedBlocker 等待,则池可能会启动更多线程来补偿。 commonPool 的并行度默认为“CPU 内核数减一”,因此当将启动的非池线程合并为助手时,生成的并行度将使用所有 CPU 内核。

    当您提交的作业多于线程时,它们将被排入队列。将几个作业加入队列有助于利用线程,因为并非所有作业都可以在完全相同的时间运行,因此耗尽工作的线程可能会从其他线程中窃取作业,但过多地拆分工作可能会产生不必要的开销。

    因此,您可以使用ForkJoinTask.getSurplusQueuedTaskCount() 来获取当前不太可能被其他线程窃取的待处理作业数量,并且仅在低于一个小阈值时才拆分。正如其文档所述:

    这个值对于是否分叉其他任务的启发式决策可能很有用。在 ForkJoinTasks 的许多用法中,在稳定状态下,每个工作人员应致力于保持少量的恒定剩余任务(例如,3 个),并在超过此阈值时在本地处理计算。

    所以这是决定是否进一步拆分工作的条件。由于此数字反映了空闲线程何时窃取您创建的作业,因此当作业具有不同的 CPU 负载时​​会导致平衡。此外,它的工作方式相反,如果池是共享的(如公共池)并且线程已经很忙,它们将不会接您的工作,剩余计数将保持高位,然后您将自动停止拆分。

    【讨论】:

    • 这个解释真棒!完全解决我的问题。只是一个后续:如果线程继续分裂而不检查排队的任务会有什么后果?我知道它会产生很多开销,但是所有线程都会挂起或者它们将继续以最低速度执行是灾难吗?
    • 让大量工作排队本身不是问题。但是,像invokeAll(new SubJob(), new SubJob()) 这样将大量作业排入队列有两种可能性,a)它真正等待并启动一个新的补偿线程(可能有很多线程),或者 b)它将通过执行其中的一个作业在invokeAll 中提供帮助-place 增加嵌套方法调用的数量。我想,它是 b),只要你有相当平衡的分割,这不是问题,因为这意味着 log₂ n 深度,但如果分割不平衡,你会冒StrackOverflowError 的风险。
    • 当然,这一切都取决于实际数字。想象一下像IntStream.range(0, 1_000_000_000).parallel(). … 这样的并行流。你肯定不希望每个元素都有一个排队的工作。
    • 但是,不会出现死锁或类似情况,只是内存消耗非常高且性能低下。
    • 非常感谢您详尽的回答!
    猜你喜欢
    • 2021-11-19
    • 2015-10-13
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 2020-01-09
    相关资源
    最近更新 更多