Dois-je toujours utiliser un courant parallèle lorsque cela est possible?
Avec Java 8 lambdas et il est facile de parcourir les collections comme des ruisseaux, et tout aussi facile à utiliser un courant parallèle. Deux exemples de les docs, le second en utilisant parallelStream:
myShapesCollection.stream()
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));
myShapesCollection.parallelStream() //<-- This one uses parallel
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));
Tant que je ne se soucient pas de l'ordre, ne serait-il toujours être intéressant d'utiliser le parallèle? On pourrait penser qu'il est plus rapide la division du travail sur plus de cœurs.
Existe-il d'autres considérations? Quand doit-courant parallèle être utilisé et à quel moment les non-parallèle-elle être utilisée?
(Cette question est posée pour déclencher une discussion au sujet de comment et quand utiliser les flux parallèles, pas parce que je pense toujours à l'aide de eux est une bonne idée).
Vous devez vous connecter pour publier un commentaire.
Un courant parallèle a beaucoup plus de frais généraux par rapport à un séquentiel. Coordonner les fils prend beaucoup de temps. Je voudrais utiliser séquentielle flux par défaut et ne prennent en considération parallèles si
J'ai une énorme quantité d'éléments à traiter (ou le traitement de chaque élément prend du temps et est parallélisable)
J'ai un problème de performance, en premier lieu,
Je n'ai pas déjà exécuté le processus dans un environnement multithread (par exemple: dans un conteneur web, si j'ai déjà beaucoup de demandes à traiter en parallèle, l'ajout d'une couche supplémentaire de parallélisme à l'intérieur de chaque demande pourrait avoir plus négatifs que d'effets positifs)
Dans votre exemple, le rendement sera de toute façon être entraînée par l'accès synchronisé à
System.out.println()
, et de faire de ce processus parallèle n'aura aucun effet, ou même négative.En outre, n'oubliez pas que les ruisseaux parallèles ne pas magique pour résoudre tous les problèmes de synchronisation. Si une ressource partagée est utilisée par les prédicats et fonctions utilisées dans le processus, vous devrez vous assurez que tout est thread-safe. En particulier, les effets secondaires sont des choses que vous avez vraiment besoin de vous inquiéter si vous allez en parallèle.
En tout cas, de mesurer, de ne pas le deviner! Seulement une mesure de vous dire si le parallélisme en vaut la peine ou pas.
Runnable
que j'appellestart()
de les utiliser commeThreads
, est-il ok pour changer cela à l'aide de java 8 flux de données dans un.forEach()
parallélisée ? Puis je serais en mesure de dépouiller le fil code de la classe. Mais existe-il des inconvénients?In any case, measure, don't guess! Only a measurement will tell you if the parallelism is worth it or not.
. En parallèle de lire sur la liste de pousser java pour frayer les threads de lire la liste. Lorsque vous travaillez avec des processus qui ne sont pas de frai fils parallélisme devient utile. Par exemple l'exécution d'une tâche au printemps managed bean où le printemps en garde un thread pour le traitement de la tâche à l'intérieur de la fève. Tous les scénarios de traitement est différent et, sans peaufinage et la mesure ce qui améliore le traitement ou non, elle sera incomplète analogie.Le Flux de l'API a été conçu pour rendre plus facile l'écriture des calculs dans un chemin qui a été prélevée à l'écart de la façon dont ils seraient exécutés, faire de la commutation entre les parallèles et séquentielles facile.
Cependant, juste parce qu'elle est facile, ne signifie pas que c'est toujours une bonne idée, et en fait, c'est un mauvais idée de tout laisser tomber,
.parallel()
tous sur la place tout simplement parce que vous le pouvez.Tout d'abord, notez que le parallélisme n'offre pas d'avantages autres que la possibilité d'une exécution plus rapide lorsque plus de cœurs sont disponibles. Une exécution parallèle impliquera toujours plus de travail que d'un séquentiel, parce que, en plus de résoudre le problème, il faut aussi effectuer la répartition et la coordination des sous-tâches. L'espoir est que vous serez en mesure d'obtenir pour la réponse rapide en décomposant le travail sur plusieurs processeurs; si cela se produit dépend de beaucoup de choses, y compris la taille de votre ensemble de données, combien de calcul que vous faites sur chaque élément, la nature du calcul (en particulier, le traitement d'un élément d'interagir avec le traitement des autres?), le nombre de processeurs disponibles, et le nombre d'autres tâches concurrentes pour ces processeurs.
De plus, notez que le parallélisme également expose souvent des non-déterminisme dans le calcul qui est souvent caché par séquentielle implémentations; parfois, cela n'a pas d'importance, ou peut être atténué en limitant les opérations (c'est à dire, la réduction des opérateurs doit être apatride et associatif.)
Dans la réalité, parfois parallélisme permettra d'accélérer votre calcul, parfois, il ne sera pas, et parfois il va même jusqu'à le ralentir. Il est préférable de développer d'abord à l'aide de l'exécution séquentielle et ensuite appliquer le parallélisme où (Un) vous savez qu'il ya effectivement des avantages à l'augmentation des performances et (B) qu'il va effectivement offrir des performances accrues. (A) est un problème d'entreprise, pas d'ordre technique. Si vous êtes un spécialiste, vous aurez généralement être en mesure de regarder le code et de déterminer (B), mais le smart chemin est à mesurer. (Et ne même pas la peine jusqu'à ce que vous êtes convaincu de (A); si le code est assez rapide, mieux appliquer votre cerveau cycles d'ailleurs.)
Le plus simple modèle de performance pour le parallélisme est le "NQ" modèle, où N est le nombre d'éléments, et Q est le calcul par élément. En général, vous avez besoin du produit NQ dépasser un certain seuil avant que vous commencez à obtenir un avantage de performance. Pour un faible Q problème comme "ajouter des nombres de 1 à N", vous aurez généralement voir un équilibre entre N=1000 et N=10000. Avec plus de Q problèmes, vous verrez breakevens à des seuils inférieurs.
Mais la réalité est assez compliqué. Donc, jusqu'à ce que vous atteindre experthood, d'abord identifier lorsque le traitement séquentiel est réellement vous coûter quelque chose, et puis de mesurer si le parallélisme de l'aide.
findAny
au lieu defindFirst
...myListOfURLs.stream().map((url) -> downloadPage(url))...
).if
vsswitch
: utilisez simplement selon ce qui est sémantiquement correct, et laisser le compilateur de déterminer la meilleure façon de appliquer il.ForkJoinPool.commonPool()
et vous ne voulez pas de blocage des tâches d'y aller.J'ai regardé un des présentations de Brian Goetz (Langage Java Architecte & spécification de plomb pour les Expressions Lambda). Il explique en détail la suite de 4 points à prendre en considération avant d'aller à la parallélisation:
Découpage /décomposition des coûts
– Parfois, le fractionnement est plus cher que de simplement faire le travail!
Tâche la répartition /gestion des coûts
– On peut faire beaucoup de travail dans le temps de travail à la main à un autre thread.
Résultat de la combinaison des coûts
– Parfois, la combinaison implique la copie de beaucoup de données. Par exemple, l'ajout de numéros n'est pas cher alors que la fusion des ensembles est cher.
Localité
– L'éléphant dans la pièce. C'est un point important qui tout le monde peut manquer. Vous devriez considérer les défauts de cache, si un CPU attend les données en raison de défauts de cache alors que vous ne voudriez pas de gagner quoi que ce soit par la parallélisation. C'est pourquoi la matrice de sources paralléliser le meilleur comme le prochain indices (près de l'actuel indice) sont mises en cache et il y a peu de chances que le CPU ferait l'expérience d'un cache miss.
Il mentionne également relativement simple formule pour déterminer une chance de parallèle speedup.
NQ Modèle:
où,
N = nombre d'éléments de données
Q = quantité de travail par poste
JB a frappé le clou sur la tête. La seule chose que je peux ajouter, c'est que Java 8 ne fait pas un pur traitement parallèle, il ne paraquential. Oui j'ai écrit l'article et j'ai fait des F/J pendant trente ans, donc, je ne comprends le problème.
ArrayList
/HashMap
.D'autres réponses ont déjà couvert de profilage pour éviter l'optimisation prématurée et des frais généraux dans le traitement en parallèle. Cette réponse explique le choix idéal pour les structures de données parallèles en streaming.
Source: Item #48 user de Prudence Lors de la Prise de Flux Parallèle, Efficace Java 3e par Joshua Bloch