英文:
ForkJoinFramwork, call compute() directly without explicit ForkJoinPool/ExecutorService
问题
Q: 当直接调用一个扩展了RecursiveAction/Task<V>的类"X"中的compute()方法时会发生什么?
不像下面这样显式地调用ForkJoinPool:
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<?> task = new X(...);
pool.invoke(task);
而是像下面这样调用一个函数,仍然会产生类似的结果:
// X扩展了RecursiveAction/Task<V>,这也意味着它是ForkJoinTask的子类。
X x = new X(...);
x.compute();
当在类X内部调用fork() / invokeAll()方法时(没有显式指定ExecutorService),会发生什么?
我的假设是,当调用扩展类X内部的fork()或invoke()方法时,如果没有显式指定池,则会自动将新任务提交到ForkJoinPool.commonPool()。但我找不到任何明确说明这种行为的文档。
(可能相关的Oracle文档引用)
> 当"main" ForkJoinTask 被显式地提交到ForkJoinPool时,或者如果它尚未参与ForkJoin计算,则通过fork()、invoke()或相关方法在ForkJoinPool.commonPool()中开始执行。
如果有任何信息或关键词,将不胜感激。
一个代码片段(注意"othertask.fork()"):
class X extends RecursiveTask<Double>{
private Double[] numbersToBeOperated;
private int start;
private int end;
public X(Double numbersToBeOperated, int start, int end){
// 定义字段,即this.* = *;
}
@Override
protected Double compute(){
if(taskDividedToBaseCase){
// 做一些操作
} else {
int middle = start + ((end - start) / 2);
RecursiveTask<Double> otherTask = new X(numbersToBeOperated, start, middle);
otherTask.fork(); // 在直接调用compute()时这里会发生什么?
return new X(numbersToBeOperated, middle, end).compute() + otherTask.join();
// 或者如果是RecursiveAction,使用invokeAll(new X(...), new X(...));
}
}
}
// 然后实例化X并直接调用X.compute()。
英文:
Q: What happens when the compute() method, in a class "X" that extends RecursiveAction/Task<V>, is directly called?
Without calling a ForkJoinPool explicitly like the following:
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<?> task = new X(...);
pool.invoke(task);
Instead a function call like the following still produce a similar result:
// X extends RecursiveAction/Task<V>, which also means it is a subclass of ForkJoinTask.
X x = new X(...);
x.compute();
What happens when the fork()/invokeAll() method inside class X is called (explicit ExecutorService is absent)?
My assumption would be, when an fork() or invoke() method inside the extended class X is called, a new task is automatically submitted to the ForkJoinPool.commonPool(), if no pool is explicitly specified. But I couldn't find any document that specifies this behavior.
(Citation from the oracle documentation that might be relative)
> A "main" ForkJoinTask begins execution when it is explicitly submitted
> to a ForkJoinPool, or, if not already engaged in a ForkJoin
> computation, commenced in the ForkJoinPool.commonPool() via fork(),
> invoke(), or related methods.
Any info or keywords would be appreciated.
A code snippet (note the "othertask.fork()"):
class X extends RecursiveTask<Double>{
private Double[] numbersToBeOperated;
private int start;
private int end;
public X(Double numbersToBeOperated, int start, int end){
// define the fields, i.e., this.* = *;
}
@Override
protected Double compute(){
if(taskDividedToBaseCase){
// do works
} else {
int middle = start + ((end - start) / 2);
RecursiveTask<Double> otherTask = new X(numbersToBeOperated, start, middle);
otherTask.fork(); // what happens here, when compute() is directly called?
return new X(numbersToBeOperated, middle, end).compute() + otherTask.join();
// or invokeAll(new X(...), new X(...)); if RecursiveAction
}
}
}
// then instantiate X and call X.compute() directly.
答案1
得分: 2
引用 java.util.concurrent.ForkJoinTask<V>.fork()
:
如果适用,安排在当前任务所在的池中异步执行此任务,否则使用ForkJoinPool.commonPool(),如果不在ForkJoinPool()中。
它确实会进入commonPool()。
还要感谢 @Holger 指出了这份文档。
英文:
Citing java.util.concurrent.ForkJoinTask<V>.fork()
:
> Arranges to asynchronously execute this task in the pool the current task is running in, if applicable, or using the
> ForkJoinPool.commonPool() if not inForkJoinPool().
It do goes to the commonPool().
Also thanks @Holger for pointing to this documentation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论