Devo usar sempre um fluxo paralelo quando possível?

Com Java 8 e lambdas é fácil iterar sobre coleções como córregos, e tão fácil de usar um fluxo paralelo. Dois exemplos de os docs , o segundo usando o 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()));
Desde que não me importe com a ordem, seria sempre benéfico usar o paralelo? Seria de pensar que é mais rápido dividir o trabalho em mais núcleos.

Há outras considerações? Quando deve ser utilizado um fluxo paralelo e quando deve o não paralelo ser usado?

(esta pergunta é feita para desencadear uma discussão sobre como e quando usar córregos paralelos, não porque eu acho que sempre usá-los é uma boa idéia.)

Author: Matsemann, 2013-12-04

4 answers

Uma corrente paralela tem uma sobrecarga muito maior em comparação com uma sequência. Coordenar os fios leva uma quantidade significativa de tempo. Eu usaria fluxos sequenciais por padrão e só consideraria os paralelos se

  • Eu tenho uma enorme quantidade de itens para processar (ou o processamento de cada item leva tempo e é paralelizável)

  • Eu tenho um problema de desempenho em primeiro lugar

  • Eu ainda não executei o processo em um multi-thread ambiente (por exemplo: em um recipiente web, se eu já tenho muitos pedidos para processar em paralelo, adicionar uma camada adicional de paralelismo dentro de cada pedido pode ter efeitos mais negativos do que positivos)

No seu exemplo, o desempenho será conduzido pelo acesso sincronizado a {[[0]}, e fazer este processo paralelo não terá nenhum efeito, ou mesmo um negativo.

Além disso, lembrem-se que correntes paralelas não resolvem magicamente todos os problemas de sincronização. Se um recurso compartilhado é usado pelos predicados e funções utilizadas no processo, você terá que se certificar de que tudo é seguro thread. Em particular, os efeitos secundários são coisas que você realmente tem que se preocupar se você vai paralelo. Em todo o caso, meça, não adivinhe! Apenas uma medida lhe dirá se o paralelismo vale a pena ou não.
 500
Author: JB Nizet, 2017-05-10 03:07:16

A API Stream foi concebida para facilitar a escrita de computações de uma forma que foi abstraída de como elas seriam executadas, tornando fácil a troca entre sequencial e paralelo.

No entanto, só porque é fácil, não quer dizer que seja sempre uma boa ideia, e na verdade, é uma má ideia cair por todo o lado simplesmente porque pode.

Primeiro, note que o paralelismo não oferece outros benefícios além da possibilidade de execução mais rápida quando mais núcleos estão disponíveis. Uma execução paralela sempre envolverá mais trabalho do que sequencial, porque além de resolver o problema, também tem que executar o envio e coordenação de sub-tarefas. A esperança é que você vai ser capaz de obter a resposta mais rápida, dividindo o trabalho entre vários processadores; se isso realmente acontece depende de um monte de coisas, incluindo o tamanho de seu conjunto de dados, quanto de computação que você está fazendo em cada elemento, a natureza do computação (especificamente, o processamento de um elemento interage com o processamento de outros?), o número de processadores disponíveis e o número de outras tarefas concorrentes para esses processadores.

Além disso, note que o paralelismo também muitas vezes expõe o não-determinismo na computação que é muitas vezes escondido por implementações sequenciais; às vezes isso não importa, ou pode ser mitigado restringindo as operações envolvidas (ou seja, os operadores de redução devem ser apátridas e associativas.)

Na realidade, às vezes, o paralelismo acelera a nossa computação, outras vezes não, e outras vezes até a atrasa. É melhor desenvolver primeiro usando a execução sequencial e, em seguida, aplicar o paralelismo onde (a) você sabe que há realmente benefício para o aumento do desempenho e (B) que ele realmente irá proporcionar um aumento do desempenho. (A) é um problema de negócios, não um problema técnico. Se você é um especialista em performance, você geralmente será capaz de olhar para o código e determinar (B), mas o caminho inteligente é medir. (E, não se incomode até que você esteja convencido de (a); se o código é rápido o suficiente, melhor aplicar seus ciclos cerebrais em outro lugar.)

O modelo de desempenho mais simples para o paralelismo é o modelo "NQ", Onde N é o número de elementos, e Q É o cálculo por elemento. Em geral, você precisa que o NQ do produto exceda algum limiar antes de começar a obter um benefício de desempenho. Para um problema de baixo Q Como "somar números de 1 A N", você geralmente verá um intervalo entre n = 1000 E N = 10000. Com problemas de Q mais altos, você verá breakevens em limiares mais baixos.

Mas a realidade é bastante complicada. Então, até você atingir a experiência, primeiro identifique quando o processamento sequencial está realmente custando alguma coisa, e em seguida, medir se o paralelismo vai ajudar.
 176
Author: Brian Goetz, 2018-02-24 16:45:43
Vi uma das apresentações de Brian Goetz. ( Java Language Architect & specification lead for Lambda Expressions) . Ele explica em detalhe os seguintes 4 pontos a considerar antes de ir para a parallelização:

Custos de repartição / decomposição
- Às vezes dividir é mais caro do que apenas fazer o trabalho!
custos de envio / gestão da Tarefa
- Pode fazer muito trabalho no tempo que leva para o trabalho manual para outro fio.
custos de combinação de resultados
- Às vezes a combinação envolve copiar muitos dados. Por exemplo, adicionar números é barato, enquanto conjuntos de fusão é caro.
Localidade
- O elefante na sala. Este é um ponto importante que todos podem sentir falta. Você deve considerar falhas de cache, se uma CPU espera por dados por causa de falhas de cache, então você não ganharia nada pela parallelização. É por isso que fontes baseadas em array paralelizam o melhor como o próximo índices (perto do índice atual) são cache e há menos chances de que CPU iria experimentar uma falha de cache.

Ele também menciona uma fórmula relativamente simples para determinar uma chance de aceleração paralela.

Modelo NQ:

N x Q > 10000

em que,
N = Número de rubricas
Q = quantidade de trabalho por item

 40
Author: Ram Patra, 2016-08-21 17:40:37
O JB acertou em cheio na cabeça. A única coisa que posso acrescentar é que Java8 não faz processamento paralelo puro, faz paraquential Sim eu escrevi o artigo e tenho feito F/J por trinta anos então eu entendo a questão.
 11
Author: edharned, 2013-12-04 19:39:33