0Pricing
Java Academy · Leçon

Quand le parallélisme est utile

Facteurs liés à la charge et au volume de données

Quand le parallélisme est utile est une leçon Java Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Java Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Java Academy comprend 4 leçons au total.

Le parallel a un coût

Le passage en parallel ajoute des coûts : division des données, distribution des tâches et fusion des résultats. Il n’est rentable que lorsque ces coûts sont inférieurs au temps gagné.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long sum = IntStream.rangeClosed(1, 10_000_000)
            .parallel()
            .asLongStream()
            .sum();
        System.out.println(sum);
    }
}

Facteur 1 : taille des données (N)

Une valeur élevée de N amortit le coût fixe du parallel. Une règle approximative est d’attendre plusieurs dizaines de milliers d’éléments avant que le parallel devienne intéressant.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long count = IntStream.rangeClosed(1, 5_000_000)
            .parallel()
            .filter(n -> n % 7 == 0)
            .count();
        System.out.println(count);
    }
}

Facteur 2 : travail par élément (Q)

Le coût Q du traitement de chaque élément est important. Un travail coûteux par élément (calcul intensif) tire profit du parallel même pour une valeur de N plus faible.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long primes = IntStream.rangeClosed(2, 200_000)
            .parallel()
            .filter(Main::isPrime)
            .count();
        System.out.println(primes);
    }

    static boolean isPrime(int n) {
        for (int i = 2; (long) i * i <= n; i++)
            if (n % i == 0) return false;
        return true;
    }
}

L’intuition de N × Q

Considérez le travail utile total comme N × Q. Plus ce produit est grand, plus le parallel peut être avantageux. Une petite valeur de N ou un Q insignifiant le justifie rarement.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        double sum = IntStream.rangeClosed(1, 1_000_000)
            .parallel()
            .mapToDouble(n -> Math.sqrt(n) * Math.log(n + 1))
            .sum();
        System.out.println(sum);
    }
}

Facteur 3 : capacité de division

Les sources de données qui se divisent rapidement et uniformément se parallélisent bien : les tableaux, ArrayList et IntStream.range. LinkedList et les sources fondées sur des itérateurs se divisent mal.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 1_000_000; i++) list.add(i);
        long even = list.parallelStream().filter(n -> n % 2 == 0).count();
        System.out.println(even);
    }
}

Bonne source : tableaux et plages

Les plages de types primitifs ont une taille connue et se divisent en O(1), ce qui en fait des sources parallel idéales.

import java.util.stream.LongStream;

public class Main {
    public static void main(String[] args) {
        long sum = LongStream.rangeClosed(1, 20_000_000)
            .parallel()
            .sum();
        System.out.println(sum);
    }
}

Source médiocre : générateurs itératifs

Stream.iterate produit les éléments séquentiellement par définition ; il ne peut donc pas se diviser avant que les éléments soient matérialisés. C’est une source parallel peu efficace.

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        long count = Stream.iterate(1, n -> n + 1)
            .limit(1_000_000)
            .parallel()
            .filter(n -> n % 2 == 0)
            .count();
        System.out.println(count);
    }
}

Facteur 4 : étape de fusion peu coûteuse

Le parallel nécessite un moyen peu coûteux de combiner les résultats partiels. sum et count se fusionnent trivialement ; la construction d’une liste triée ou l’utilisation d’un collecteur nécessitant un arbre volumineux entraîne une fusion coûteuse.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int max = IntStream.rangeClosed(1, 5_000_000)
            .parallel()
            .map(n -> n % 1000)
            .max()
            .getAsInt();
        System.out.println(max);
    }
}

Éviter pour les tâches limitées par les E/S

Les flux parallel ciblent les tâches limitées par le CPU dans le groupe fork-join. Les E/S bloquantes saturent le groupe partagé et nuisent à l’ensemble de l’application. Utilisez plutôt des exécuteurs dédiés aux E/S.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long total = IntStream.rangeClosed(1, 1_000_000)
            .parallel()
            .mapToLong(n -> (long) n * n)
            .sum();
        System.out.println(total);
    }
}

Mesurer plutôt que deviner

La seule manière fiable de savoir si le parallel est avantageux consiste à effectuer un test de performance avec des données réalistes. L’intuition concernant les performances est souvent erronée.

import java.util.stream.LongStream;

public class Main {
    public static void main(String[] args) {
        long start = System.nanoTime();
        long sum = LongStream.rangeClosed(1, 50_000_000).parallel().sum();
        long ms = (System.nanoTime() - start) / 1_000_000;
        System.out.println("sum=" + sum + " took ~" + ms + "ms");
    }
}

Liste de vérification pratique

Privilégiez le parallel lorsque toutes les conditions suivantes sont réunies :

  • N est grand et/ou le travail par élément est coûteux.
  • La source peut être divisée (tableau, ArrayList, plage).
  • La fusion est peu coûteuse et associative.
  • Le travail est limité par le CPU et n’effectue pas d’E/S bloquantes.
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        double avg = IntStream.rangeClosed(1, 10_000_000)
            .parallel()
            .mapToDouble(Math::sqrt)
            .average()
            .getAsDouble();
        System.out.println(avg);
    }
}

Vérification rapide

Quel scénario constitue le meilleur candidat pour un flux parallel ?

Récapitulatif

Vous avez appris quand le parallel est utile :

  • L’avantage augmente avec N × Q (taille des données multipliée par le coût par élément).
  • Il faut une source divisible (tableaux, ArrayList, plages).
  • Il faut une fusion associative peu coûteuse.
  • Limitez le travail au CPU, évitez les E/S bloquantes et mesurez toujours les performances.

Questions Fréquemment Posées

La leçon « Quand le parallélisme est utile » est-elle gratuite ?

Oui — le texte complet de « Quand le parallélisme est utile » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Java Academy, passe à CoddyKit PRO. Le cours Java Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Quand le parallélisme est utile » ?

Facteurs liés à la charge et au volume de données Tu pratiques Java Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Java Academy ?

Aucune expérience préalable n'est requise. Java Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Quand le parallélisme est utile » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Java Academy ?

Oui. Chaque leçon Java Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Créer des flux parallèles
  2. Quand le parallélisme est utile
  3. Sûreté vis-à-vis des threads et effets secondaires
  4. Pièges courants
← Retour à Java Academy