一般来说,你不知道在尝试Advisor或forEachRemaining的消费者中做了多少工作.流管道和FJP都不知道这一点,因为它取决于用户提供的代码.它可以比分割程序快得多或慢得多.例如,您可能有两个元素的输入,但每个元素的处理需要一个小时,因此拆分此输入是非常合理的.
我通常尽可能多地分割输入.有三个技巧可以用来改善分裂:
>如果难以均匀分割,但您可以跟踪(或至少粗略估计)每个子部分的大小,可以自由分割.流的实现将在更大的部分进一步分裂.不要忘记SIZED和SUBSIZED的特点.
>将分割的重要部分移动到下一个tryAdvance / forEachRemaining调用.例如,假设你有一个已知的排列数,而在trySplit中,你将会跳到其他排列.这样的事情
public class MySpliterator implements Spliterator {
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 trySplit() {
if(limit - position <= 1)
return null;
long newPosition = (position+limit)>>>1;
Spliterator prefix =
new MySpliterator(position, newPosition, currentPermutation);
this.position = newPosition;
this.currentPermutation = calculatePermutation(newPosition); // hard part
return prefix;
}
...
}
将硬件部分移动到下一个tryAdvance调用,如下所示:
@Override
public Spliterator trySplit() {
if(limit - position <= 1)
return null;
long newPosition = (position+limit)>>>1;
Spliterator 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
...
}
这样,硬件部分也将与前缀处理并行执行.>如果您目前没有这么多的元素(例如,不到10个),并且分配被要求,那么提升到一半的元素收集到数组中可能是很好的,然后创建一个基于数组的分割器对于这个前缀(类似于在AbstractSpliterator.trySplit()中完成).在这里,您可以控制所有代码,因此您可以提前测量trySplit的正常速度,而不是tryAdvance,并且在切换到基于阵列的拆分时估计阈值.