我知道there is overhead in setting up是并行Stream
的处理,并且如果项目很少或每个项目的处理都很快,则在单个线程中的处理会更快。
但是,对于 trySplit()
是否有类似的阈值,即将问题分解成较小的块会适得其反吗?我正在通过类比思考,将合并排序切换为最小块的插入排序。
如果是这样,阈值是否取决于trySplit()
过程中tryAdvance()
和consuming项目的相对成本?考虑一个拆分操作,它比推进数组索引要复杂得多,例如,拆分按词法排序的多集置换。是否有约定让客户在创建并行流时指定拆分的下限,具体取决于其使用者的复杂性?启发式Spliterator
可以用来估计下限本身吗?
或者,将Spliterator
的下限设置为1并让偷窃算法选择是否继续拆分始终是安全的吗?
最佳答案
通常,您不知道在传递给tryAdvance
或forEachRemaining
的使用者中完成了多少工作。流管道和FJP都不知道这一点,因为它取决于用户提供的代码。它可能比拆分过程快得多或慢得多。例如,您可能有两个元素的输入,但是每个元素的处理需要一个小时,因此拆分此输入是非常合理的。
我通常会尽可能地分割输入。可以使用三种技巧来改善拆分:
SIZED
和SUBSIZED
特性。 tryAdvance
/forEachRemaining
调用。例如,假设您具有已知数量的排列,并且在trySplit
中您将跳转到其他排列。像这样的东西:public class MySpliterator implements Spliterator<String> {
private long position;
private String currentPermutation;
private final long limit;
MySpliterator(long position, long limit, String currentPermutation) {
this.position = position;
this.limit = limit;
this.currentPermutation = currentPermutation;
}
@Override
public Spliterator<String> trySplit() {
if(limit - position <= 1)
return null;
long newPosition = (position+limit)>>>1;
Spliterator<String> prefix =
new MySpliterator(position, newPosition, currentPermutation);
this.position = newPosition;
this.currentPermutation = calculatePermutation(newPosition); // hard part
return prefix;
}
...
}
将难的部分移至下一个
tryAdvance
调用,如下所示:@Override
public Spliterator<String> trySplit() {
if(limit - position <= 1)
return null;
long newPosition = (position+limit)>>>1;
Spliterator<String> prefix =
new MySpliterator(position, newPosition, currentPermutation);
this.position = newPosition;
this.currentPermutation = null;
return prefix;
}
@Override
public boolean tryAdvance(Consumer<? super String> action) {
if(currentPermutation == null)
currentPermutation = calculatePermutation(position); // hard part
...
}
这样,最困难的部分也将与前缀处理并行执行。
AbstractSpliterator.trySplit()
中的操作)。在这里,您可以控制所有代码,因此可以提前测量正常的trySplit
比tryAdvance
慢多少,并估算应切换到基于数组的拆分时的阈值。 关于java - 分离器何时应停止分离?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31974261/