TL / DR : невозможно.
Кажется, что обработка неограниченных потоков параллельно с методом короткого замыкания, чтобы найти самые ранние вхождения (в порядке потока) чего-либо, невозможна полезным способом («полезный» означает лучше, чем последовательный, с точки зрения времени).чтобы найти результат).
Объяснение Я попробовал пользовательскую реализацию AbstractIntSpliterator, которая разделяет поток не по разделам (1-100, 101-200, ...), а вместо этого разделяет ихчередование ([0, 2, 4, 6, 8, ...], [1, 3, 5, 6 ...]).Это работает правильно в последовательном случае:
/**
* Provides numbers starting at n, on split splits such that child iterator and
* this take provide interleaving numbers
*/
public class InterleaveSplitIntSplitIterator extends Spliterators.AbstractIntSpliterator {
private int current;
private int increment;
protected InterleaveSplitIntSplitIterator(int start, int increment) {
super(Integer.MAX_VALUE,
Spliterator.DISTINCT
// splitting is interleaved, not prefixing
// | Spliterator.ORDERED
| Spliterator.NONNULL
| Spliterator.IMMUTABLE
// SORTED must imply ORDERED
// | Spliterator.SORTED
);
if (increment == 0) {
throw new IllegalArgumentException("Increment must be non-zero");
}
this.current = start;
this.increment = increment;
}
@Override
public boolean tryAdvance(IntConsumer action) {
// Don't benchmark with this on
// System.out.println(Thread.currentThread() + " " + current);
action.accept(current);
current += increment;
return true;
}
// this is required for ORDERED even if sorted() is never called
@Override
public Comparator<? super Integer> getComparator() {
if (increment > 0) {
return null;
}
return Comparator.<Integer>naturalOrder().reversed();
}
@Override
public OfInt trySplit() {
if (increment >= 2) {
return null;
}
int newIncrement = this.increment * 2;
int oldIncrement = this.increment;
this.increment = newIncrement;
return new InterleaveSplitIntSplitIterator(current + oldIncrement, newIncrement);
}
// for convenience
public static IntStream asIntStream(int start, int increment) {
return StreamSupport.intStream(
new InterleaveSplitIntSplitIterator(start, increment),
/* no, never set parallel here */ false);
}
}
Однако такие потоки не могут иметь характеристики Spliterator.ORDERED, поскольку
Если это так, этот Spliterator гарантирует, что метод {@link #trySplit}
разделяет строгий префикс элементов
, и это также означает, что такой поток не может сохранять свои отсортированные характеристики, потому что
Spliterator, который сообщает {@code SORTED}
, также должен сообщать {@code ORDERED}
Таким образом, мой параллельный сплиттератор имеет (несколько) перемешанные числа, которые должны быть исправлены путем сортировки перед применением предела, что плохо работает с бесконечными потоками (в общем случае).
Таким образом, все решения для этого должны использовать сплиттератор, который разбивает на фрагменты или префиксные данные, которые затем используются в произвольном порядке, что приводит к обработке многих числовых диапазонов за пределами фактического результата, становясь) в целом медленнее, чем последовательное решение.
Таким образом, кроме ограничения диапазона номеровТест, кажется, не может быть решения с использованием параллельного потока.Проблема заключается в спецификации, требующей, чтобы характеристики ORDERED разделяли поток с помощью префикса, вместо того, чтобы предоставлять различные средства повторной сборки упорядоченного потока, полученного из нескольких разделителей.
Однако решение, использующее последовательный поток с параллельной обработкой (буферизованной)входные данные все еще возможны (но не так просто, как вызов parallel()
).