Spliterator:並列処理のための分割
カスタムSpliteratorを実装し、ドメインデータを分割可能なストリームソースとして扱えるようにします。
「Spliterator:並列処理のための分割」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
Spliteratorとは
Spliterator(分割可能なイテレーター)は、ストリームの基盤となる仕組みです。要素を反復処理し、並列処理のために自身を2つの部分に分割できます。
Spliteratorの主なメソッド
主なメソッドは4つあります。tryAdvance(1つの要素を処理)、forEachRemaining(残りのすべてを処理)、trySplit(2つに分割)、estimateSize(要素数の推定)です。
Spliterator<Integer> sp = List.of(1,2,3,4,5,6).spliterator();
Spliterator<Integer> half = sp.trySplit(); // splits off first ~half
half.forEachRemaining(System.out::println); // 1 2 3
sp.forEachRemaining(System.out::println); // 4 5 6Spliteratorの特性
Spliteratorはビットフラグで特性を宣言します。SIZED、ORDERED、DISTINCT、SORTED、NONNULL、IMMUTABLE、CONCURRENT、SUBSIZEDです。
Spliterator<String> sp = List.of("a","b","c").spliterator();
System.out.println(Integer.toBinaryString(sp.characteristics()));
// Characteristics include ORDERED, SIZED, SUBSIZEDtrySplitの仕組み
trySplit()は、残りの要素のおよそ半分をカバーする新しいSpliteratorを返します。元のSpliteratorは残りの半分をカバーします。分割できない場合はnullを返します。
// ArrayList Spliterator splits efficiently at midpoint:
// [0,1,2,3,4,5] -> [0,1,2] (new) + [3,4,5] (original)カスタムSpliteratorを構築する
Spliterator<T>を実装すると、カスタムデータ構造をストリームのソースとして公開できます。並列性を有効にするには、trySplitを定義します。
public class RangeSpliterator implements Spliterator<Integer> {
private int start, end;
public RangeSpliterator(int start, int end) { this.start=start; this.end=end; }
public boolean tryAdvance(Consumer<? super Integer> action) {
if (start >= end) return false;
action.accept(start++); return true;
}
public Spliterator<Integer> trySplit() {
int mid = (start + end) / 2;
if (mid <= start) return null;
RangeSpliterator prefix = new RangeSpliterator(start, mid);
this.start = mid; return prefix;
}
public long estimateSize() { return end - start; }
public int characteristics() { return ORDERED | SIZED | SUBSIZED | IMMUTABLE; }
}Spliteratorからストリームを作成する
StreamSupport.stream(spliterator, parallel)を使用すると、任意のspliteratorからストリームを作成できます。これは、カスタムデータソースとStream APIをつなぐ橋渡しです。
Spliterator<Integer> sp = new RangeSpliterator(0, 1_000_000);
Stream<Integer> stream = StreamSupport.stream(sp, true); // true = parallel
long count = stream.filter(n -> n % 2 == 0).count();
System.out.println(count); // 500000二分木用のSpliterator
カスタムSpliteratorを使うと、木構造のようなリスト以外のデータ構造でも並列処理を有効にできます。trySplitは左部分木のspliteratorを返し、右部分木を保持します。
並列処理の効率と分割品質
並列ストリームは、1つのスレッドで処理できる大きさになるまでチャンクを再帰的に分割します。適切に分割するには、estimateSizeが正確で、分割後のサイズがほぼ均等である必要があります。
一括処理のためのforEachRemaining
分割が不要な場合は、forEachRemainingをオーバーライドすると、ループ内でtryAdvanceを要素ごとに呼び出すオーバーヘッドを避け、一括処理を行えます。
@Override
public void forEachRemaining(Consumer<? super Integer> action) {
for (int i = start; i < end; i++) action.accept(i);
start = end; // mark as exhausted
}SpliteratorとIteratorの比較
Iterator: 逐次処理のみ、サイズのヒントなし、分割不可。Spliterator: 並列処理に対応し、特性とサイズの推定値を提供する、Stream API向けの仕組みです。
確認問題
分割できない場合、trySplit()は何を返しますか。
振り返り
Spliteratorは並列ストリームのエンジンです。tryAdvance、trySplit、estimateSize、characteristicsを実装すると、カスタムデータ構造をストリームとして公開できます。StreamSupport.stream(sp, true)を使用すると並列化できます。
よくある質問
「Spliterator:並列処理のための分割」レッスンは無料ですか?
はい。「Spliterator:並列処理のための分割」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「Spliterator:並列処理のための分割」で何を学びますか?
カスタムSpliteratorを実装し、ドメインデータを分割可能なストリームソースとして扱えるようにします。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「Spliterator:並列処理のための分割」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ネストしたコレクションに対するflatMap
- 並列ストリーム:性能と注意点
- Spliterator:並列処理のための分割
- iterateとgenerateによる無限ストリーム