並列ストリームのStream.spliteratorの奇妙な動作

Tagir Valeev:

私が書いているライブラリの低レベルの操作に直接ストリームスプリッターを使用しています。最近、ストリームスプリッターを使用してtryAdvance/trySplit呼び出しをインターリーブする、非常に奇妙な動作が見つかりました問題を示す簡単なコードは次のとおりです。

import java.util.Arrays;
import java.util.Spliterator;

public class SpliteratorBug {
    public static void main(String[] args) {
        Integer[][] input = { { 1 }, { 2, 3 }, { 4, 5, 6 }, { 7, 8 }, { 9 } };
        Spliterator<Integer> spliterator = Arrays.stream(input).parallel()
                .flatMap(Arrays::stream).spliterator();
        spliterator.trySplit();
        spliterator.tryAdvance(s -> {});
        spliterator.trySplit();
        spliterator.forEachRemaining(System.out::println);
    }
}

出力は

5
6
9

ご覧のとおり、フラットマッピングの後、から1までの連続した番号の順序付けられたストリームを取得する必要があり9ます。スプリテレーターを1回分割したので、中間の場所にジャンプするはずです。次に、その要素を使用して、もう一度分割します。その後、残りのすべての要素を印刷します。ストリームテールからいくつかの連続した要素があると思います(おそらくゼロ要素ですが、それでも問題ありません)。しかし、私が得るものは5、そして6、突然ジャンプし9ます。

私は現在、JDKのスプリテレーターがこのように使用されていないことを知っています。これらは常に走査の前に分割されます。ただし、公式ドキュメントでは、明示的にtrySplitafter を呼び出すことを禁止していませんtryAdvance

コレクション、配列、生成されたソースなどから直接作成されたスプリッターを使用した場合、この問題は見られませんでした。この問題は、スプリッターが中間の並列ストリームから作成された場合にのみ観察されましたflatMap

だから問題は、私はバグにぶつかったのか、それともこの方法でスプリッターを使用することが明示的に禁止されているのか?

ミーシャ:

AbstractWrappingSpliteratorと会社のソースから見ることができるものから、あなたtryAdvanceがの場合、flatMap(4,5,6)の出力はバッファーに入れられ、その後4が消費されて(5,6)がバッファーに残ります。次に、trySplit正しく(7,8)を新しいものに分割しSpliterator、9を古いものに残しますが、バッファリングされた(5,6)は古いままSpliteratorです。

これはバグのようです。バッファを新しいものに渡すか、バッファが空でない場合はSpliterator戻りnull、分割を拒否する必要があります。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事