【问题标题】:Java 7: Fork/Join FrameworkJava 7:分叉/连接框架
【发布时间】:2011-04-01 06:40:41
【问题描述】:

谁能解释一下 Fork/Join 是什么?

【问题讨论】:

    标签: java java-7 fork-join


    【解决方案1】:

    我将回答什么是 Fork Join 并行性。这是在许多系统中广泛用于实现并发的并行设计模式之一。我会用一个例子来解释这个设计模式。

    例如,假设我们有执行一系列任务的程序:

    A -> B -> C -> D. 这里 A,B,C,D 是任务。

    • A 需要 8 秒
    • B 需要 4 秒
    • C 需要 6 秒
    • D 需要 7 秒

    所以这个程序执行总共需要 8+4+6+7 = 25 秒。

    现在您发现任务 A、B、C 是独立的,而 D 取决于 A、B、C 任务的结果。现在你可能会有一种感觉,我们可以同时开始执行 B,而不是等待 A 完成。任务 C 相同 可以与A和B同时启动任务。您可以做的是:您可以通过主线程调用3个新线程并分配给它们A,B,C任务并在开始执行任务D之前等待结果。如果您的机器有多个内核,那么这些线程可以并行运行。

    现在程序的执行时间是:

    max(time_taken_A,_B,_C) + time_taken_D + threading_overhead_time

    几乎等于 = 8 + 7 + k = 15 + k;

    在 fork join 并行性中,只有当这些任务是独立的时,我们才能使用新线程卸载任务。否则,我们将面临竞争条件。如果您有一个程序,其中一个任务正在等待另一个任务执行,但这不依赖于其结果,那么您可以使用 fork join 并行性使用新线程卸载这两个任务,您可以获得性能提升。但总是想着头顶的穿线。如果您的任务非常轻量级,那么使用这些并行模式会因为线程创建、上下文切换开销而降低您的性能。

    【讨论】:

      【解决方案2】:

      除了已经说过的之外,fork/join 还利用了工作窃取 - 无事可做的线程可以从其他仍在忙碌的线程中窃取任务。下面是一个示例,可以帮助您了解如何使用 FJ:

      public class SumCounter extends RecursiveTask<Long> { 
      
        private final Node node; 
      
        public SumCounter(Node node) { 
          this.node = node; 
        } 
      
        @Override
        protected Long compute() { 
          long sum = node.getValue();
          List<ValueSumCounter> subTasks = new LinkedList<>(); 
      
          for(Node child : node.getChildren()) { 
            SumCounter task = new SumCounter(child); 
            task.fork(); // run asynchronously
            subTasks.add(task); 
          }
      
          for(SumCounter task : subTasks) { 
            sum += task.join(); // wait for the result 
          } 
      
          return sum;
        }
      
        public static void main(String[] args) { 
          Node root = getRootNode(); 
          new ForkJoinPool().invoke(new SumCounter(root)); 
        }
      
      }
      

      【讨论】:

        【解决方案3】:

        Fork Join 是一个新框架,它具有更易于使用的 API,用于并行、分而治之的算法。

        假设您有一个长时间运行的任务,在这种情况下,它有一个复杂的算法。您可能希望分叉大型任务,然后处理这两个任务。现在假设这两个任务仍然太大,您可以将每个任务分成两个任务(此时有四个)。

        您将继续此操作,直到每个任务都达到可接受的大小并调用算法。重要的是要知道每个任务的调用是并行完成的。当任务完成后,它会与其他任务合并并合并结果。

        这将一直持续到所有任务都已加入并返回一个任务。

        【讨论】:

          【解决方案4】:

          假设您有一组需要处理的东西。您有许多线程可以获取该集合的子集并对其进行处理。他们都同时执行此操作(fork 部分),然后等待最后一个完成(join 部分),然后返回。

          【讨论】:

          • 具有当前父级停止执行的权限,直到所有并发工作人员完成,然后然后恢复。我知道这是您的描述中固有的,但我认为值得非常明确,因为这就是真正使这与任何其他类型的明确并行性不同的所有因素。
          • 好吧,这不是分叉大量操作,执行所有操作然后加入。这是一种分而治之的方法。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-19
          • 2015-11-06
          • 1970-01-01
          • 2017-08-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多