web-dev-qa-db-ja.com

並列ストリームがForkJoinPoolのすべてのスレッドを使用しないのはなぜですか?

したがって、カスタムForkJoinPoolなしでparallelStreamを使用すると、デフォルトのForkJoinPoolを使用することになります。デフォルトでは、プロセッサの数が1つ少ないスレッドになります。

したがって、 ここに記載 (およびその質問の他の回答でも)並列性を高めるには、次のようにする必要があります。

並列ストリーム実行を独自のForkJoinPoolに送信します。yourFJP.submit(()-> stream.parallel()。forEach(doSomething));

だから、私はこれをやった:

import Java.util.Set;
import Java.util.concurrent.ExecutionException;
import Java.util.concurrent.ForkJoinPool;
import Java.util.stream.IntStream;
import com.google.common.collect.Sets;

public class Main {

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        ForkJoinPool forkJoinPool = new ForkJoinPool(1000);

        IntStream stream = IntStream.range(0, 999999);

        final Set<String> thNames = Collections.synchronizedSet(new HashSet<String>());

        forkJoinPool.submit(() -> {
            stream.parallel().forEach(n -> {

                System.out.println("Processing n: " + n);
                try {
                    Thread.sleep(500);
                    thNames.add(Thread.currentThread().getName());
                    System.out.println("Size: " + thNames.size() + " activeCount: " + forkJoinPool.getActiveThreadCount());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }).get();
    }
}

作成されているスレッドの数を確認するためにスレッド名のセットを作成し、プールにあるアクティブなスレッドの数と両方の数が16を超えないように記録しました。つまり、ここでの並列性は16を超えない(なぜ16でも)。 forkJoinPoolを使用しない場合、並列処理として4を取得します。これは、所有しているプロセッサーの数に応じています。

なぜ1000ではなく16になるのですか?

14

更新

もともとこの答えは、ForkJoinPoolがバックプレッシャーを適用し、ストリームを処理するために使用可能なアイドルワーカーが常に存在するため、規定の並列性レベルに到達しないと主張する詳細な説明でした。

それは間違っています。

実際の回答は、これが重複としてマークされた元の質問で提供されます-ストリーム処理にカスタムForkJoinPoolを使用することは公式にサポートされておらず、forEachを使用する場合、デフォルトのプール並列性が使用されますストリームスプリッターの動作を決定します。

以下は、タスクがカスタムForkJoinPoolに手動で送信されると、プールのアクティブなスレッドカウントが簡単にその並列処理レベルに達する方法の例です。

for (int i = 0; i < 1_000_000; ++i) {
   forkJoinPool.submit(() -> {
      try {
         Thread.sleep(1);
         thNames.add(Thread.currentThread().getName());
         System.out.println("Size: " + thNames.size() + " activeCount: " + forkJoinPool.getActiveThreadCount() + " parallelism: " + forkJoinPool.getParallelism());
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   });
}

Stuart Marksこれを指摘してくれてありがとうSotirios Delimanolis私の元の答えが間違っていると主張してくれてありがとう:)

11