当前位置: 首页 > 面试题库 >

fork / join框架比线程池更好吗?

施英哲
2023-03-14
问题内容

使用新的fork /
join框架
有什么好处,而不是仅在开始时将大任务简单地拆分为N个子任务,然后将它们发送到缓存的线程池(来自Executors),然后等待每个任务完成?我看不到使用fork
/ join抽象如何简化问题或使解决方案比我们多年以来的效率更高。

例如,本教程示例中的并行化模糊算法可以这样实现:

public class Blur implements Runnable {
    private int[] mSource;
    private int mStart;
    private int mLength;
    private int[] mDestination;

    private int mBlurWidth = 15; // Processing window size, should be odd.

    public ForkBlur(int[] src, int start, int length, int[] dst) {
        mSource = src;
        mStart = start;
        mLength = length;
        mDestination = dst;
    }

    public void run() {
        computeDirectly();
    }

    protected void computeDirectly() {
        // As in the example, omitted for brevity
    }
}

首先拆分,然后将任务发送到线程池:

// source image pixels are in src
// destination image pixels are in dst
// threadPool is a (cached) thread pool

int maxSize = 100000; // analogous to F-J's "sThreshold"
List<Future> futures = new ArrayList<Future>();

// Send stuff to thread pool:
for (int i = 0; i < src.length; i+= maxSize) {
    int size = Math.min(maxSize, src.length - i);
    ForkBlur task = new ForkBlur(src, i, size, dst);
    Future f = threadPool.submit(task);
    futures.add(f);
}

// Wait for all sent tasks to complete:
for (Future future : futures) {
    future.get();
}

// Done!

任务进入线程池的队列,当工作线程可用时,从队列中执行任务。只要拆分足够精细(避免特别地等待最后一个任务)并且线程池具有足够的线程(至少N个处理器)线程,则所有处理器都将全速工作,直到完成整个计算为止。

我想念什么吗?使用fork / join框架的附加价值是什么?


问题答案:

我认为基本的误解是,Fork / Join示例 并未 显示出 窃取 工作,而只是显示了某种标准的分而治之。

偷工作可能是这样的:工人B已经完成工作。他是一个善良的人,所以他环顾四周,发现工人A仍在努力工作。他走过去问:“嘿,伙计,我可以帮你。”
一个答复。“很酷,我要完成1000个单位的任务。到目前为止,我已经完成了345个工作,剩下655个工作。请把673改为1000,我将把346改为672。”
B说:“好,让我们开始吧,我们可以早些去酒吧。”

您会看到-工人即使在开始实际工作时也必须彼此沟通。这是示例中缺少的部分。

另一方面,这些示例仅显示类似“使用分包商”的内容:

工人A:“党,我有1000个工作单元。对我来说太多了。我自己做500个工作,然后将500个工作分包给别人。”
直到大任务分解成每个10个单位的小包为止。这些将由可用的工人执行。但是,如果一个小药包是一种毒药,并且比其他小药包需要更长的时间-倒霉,分裂阶段就结束了。

Fork /
Join与预先拆分任务之间唯一的区别是:当预先拆分时,您从一开始就拥有完整的工作队列。示例:1000个单位,阈值为10,因此队列中有100个条目。这些数据包分配给线程池成员。

Fork / Join比较复杂,它试图使队列中的数据包数量减少:

  • 步骤1:将一个包含(1 … 1000)的数据包放入队列
  • 步骤2:一名工作人员弹出数据包(1 … 1000),并用两个数据包替换:(1 … 500)和(501 … 1000)。
  • 步骤3:一名工作人员弹出数据包(500 … 1000)并推送(500 … 750)和(751 … 1000)。
  • 步骤n:堆栈包含以下数据包:(1..500),(500 … 750),(750 … 875)…(991..1000)
  • 步骤n + 1:弹出并执行数据包(991..1000)
  • 步骤n + 2:数据包(981..990)弹出并执行
  • 步骤n + 3:弹出数据包(961..980),并将其拆分为(961 … 970)和(971..980)。....

您会看到:在Fork / Join中,队列较小(示例中为6),并且“ split”和“ work”阶段是交错的。

当多个工作人员同时弹出并推动时,交互作用当然不是很清楚。



 类似资料:
  • fork-join框架允许在几个worker上中断某个任务,然后等待结果将它们组合起来。 它在很大程度上利用了多处理器机器的容量。 以下是fork-join框架中使用的核心概念和对象。 Fork Fork是一个过程,在这个过程中,任务将自身分成较小且独立的子任务,这些子任务可以同时执行。 语法 (Syntax) Sum left = new Sum(array, low, mid); left.

  • 本文向大家介绍Java Fork/Join框架,包括了Java Fork/Join框架的使用技巧和注意事项,需要的朋友参考一下 Fork/Join框架是ExecutorService接口的一个实现,通过它我们可以实现多进程。Fork/Join可以用来将一个大任务递归的拆分为多个小任务,目标是充分利用所有的资源尽可能增强应用的性能。 和任何ExecutorService接口的实现一样,Fork/Jo

  • 1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。比如计算1+2+。。+1

  • 主要内容:Fork,Join,ForkJoinPool,RecursiveAction,递归任务,实例框架允许在几个工作进程中断某个任务,然后等待结果组合它们。 它在很大程度上利用了多处理器机器的生产能力。 以下是框架中使用的核心概念和对象。 Fork Fork是一个进程,其中任务将其分成可以并发执行的较小且独立的子任务。 语法 这里是的子类,方法将任务分解为子任务。 Join 连接()是子任务完成执行后任务加入子任务的所有结果的过程,否则它会持续等待。 语法 这里剩下的是类的一个对象。 For

  • 本文向大家介绍Java 线程池框架,包括了Java 线程池框架的使用技巧和注意事项,需要的朋友参考一下 一、线程池结构图 二、示例 定义线程接口 1:newSingleThreadExecutor 输入结果: 2:newFixedThreadPool 输入结果: 3 :newCachedThreadPool 输入结果: 4 :ScheduledThreadPoolExecutor 输入结果: 三、

  • 在Doug Lea的论文“A Java Fork/Join Framework”中: http://gee.cs.oswego.edu/dl/papers/fj.pdf 在2.1偷工中,他说: 当工作线程遇到连接操作时,它会处理其他任务(如果可用),直到注意到目标任务已完成(通过isDone)。否则,所有任务都将在不阻塞的情况下运行到完成。 那么有人能具体告诉我这些“其他任务”来自哪里吗?它们来自