【发布时间】:2011-04-01 06:40:41
【问题描述】:
谁能解释一下 Fork/Join 是什么?
【问题讨论】:
谁能解释一下 Fork/Join 是什么?
【问题讨论】:
我将回答什么是 Fork Join 并行性。这是在许多系统中广泛用于实现并发的并行设计模式之一。我会用一个例子来解释这个设计模式。
例如,假设我们有执行一系列任务的程序:
A -> B -> C -> D. 这里 A,B,C,D 是任务。
所以这个程序执行总共需要 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 并行性使用新线程卸载这两个任务,您可以获得性能提升。但总是想着头顶的穿线。如果您的任务非常轻量级,那么使用这些并行模式会因为线程创建、上下文切换开销而降低您的性能。
【讨论】:
除了已经说过的之外,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));
}
}
【讨论】:
Fork Join 是一个新框架,它具有更易于使用的 API,用于并行、分而治之的算法。
假设您有一个长时间运行的任务,在这种情况下,它有一个复杂的算法。您可能希望分叉大型任务,然后处理这两个任务。现在假设这两个任务仍然太大,您可以将每个任务分成两个任务(此时有四个)。
您将继续此操作,直到每个任务都达到可接受的大小并调用算法。重要的是要知道每个任务的调用是并行完成的。当任务完成后,它会与其他任务合并并合并结果。
这将一直持续到所有任务都已加入并返回一个任务。
【讨论】:
假设您有一组需要处理的东西。您有许多线程可以获取该集合的子集并对其进行处理。他们都同时执行此操作(fork 部分),然后等待最后一个完成(join 部分),然后返回。
【讨论】: