O loop forEach paralelo do Java 8 aninhado apresenta desempenho ruim. Esse comportamento é esperado?

Nota: Eu já resolvi esse problema em outra postagem do SO -O uso de um semáforo dentro de uma ação de fluxo paralelo Java 8 aninhada pode DEADLOCK. Isso é um inseto? -, mas o título deste post sugeria que o problema está relacionado ao uso de um semáforo - o que distraiu um pouco a discussão. Estou criando este para enfatizar que loops aninhados podem ter um problema de desempenho - embora ambos os problemas tenham uma causa comum (e talvez porque demorei muito tempo para descobrir esse problema). (Não o vejo como duplicado, porque está enfatizando outro sintoma - mas se você o excluir).

Problema: Se você aninhar dois loops Java 8 stream.parallel (). ForEach e todas as tarefas são independentes, sem estado etc. - exceto por serem enviadas ao pool FJ comum -, o aninhamento de um loop paralelo dentro de um loop paralelo é muito pior do que o aninhamento um loop seqüencial dentro de um loop paralelo. Pior ainda: se a operação que contém o loop interno estiver sincronizada, você receberá um DEADLOCK.

Demonstração do problema de desempenho

Sem o 'sincronizado', você ainda pode observar um problema de desempenho. Você encontra um código de demonstração para isso em:http://svn.finmath.net/finmath%20experiments/trunk/src/net/finmath/experiments/concurrency/NestedParallelForEachTest.java (consulte o JavaDoc para obter uma descrição mais detalhada).

Nossa configuração aqui é a seguinte: Temos um stream.parallel (). ForEach () aninhado.

O loop interno é independente (sem estado, sem interferência etc. - exceto no uso de um pool comum) e consome 1 segundo no total, na pior das hipóteses, ou seja, se processado sequencialmente.Metade das tarefas do loop externo consome 10 segundos antes desse loop.Metade consome 10 segundos após esse loop.Portanto, todo encadeamento consome 11 segundos (pior caso) no total. * Temos um booleano que permite alternar o loop interno de paralelo () para seqüencial ().

Agora: enviando 24 tarefas de loop externo para um pool com paralelismo 8, esperamos 24/8 * 11 = 33 segundos na melhor das hipóteses (em uma máquina com 8 núcleos ou melhor).

O resultado é:

Com loop sequencial interno: 33 segundos.Com loop paralelo interno:> 80 segundos (eu tinha 92 segundos).

Pergunta, questão: Você pode confirmar esse comportamento? Isso é algo que se esperaria da estrutura? (Sou um pouco mais cuidadoso agora com a afirmação de que este é um erro, mas pessoalmente acredito que seja devido a um erro na implementação do ForkJoinTask. Observação: eu publiquei isso no interesse de simultaneidade (consultehttp://cs.oswego.edu/pipermail/concurrency-interest/2014-May/012652.html ), mas até agora não recebi confirmação de lá).

Demonstração do impasse

O código a seguir irá DEADLOCK

    // Outer loop
    IntStream.range(0,numberOfTasksInOuterLoop).parallel().forEach(i -> {
        doWork();
        synchronized(this) {
            // Inner loop
            IntStream.range(0,numberOfTasksInInnerLoop).parallel().forEach(j -> {
                doWork();
            });
        }
    });

OndenumberOfTasksInOuterLoop = 24, numberOfTasksInInnerLoop = 240, outerLoopOverheadFactor = 10000 edoWork é algum gravador de CPU sem estado.

Você encontra um código de demonstração completo emhttp://svn.finmath.net/finmath%20experiments/trunk/src/net/finmath/experiments/concurrency/NestedParallelForEachAndSynchronization.java (consulte o JavaDoc para obter uma descrição mais detalhada).

Esse comportamento é esperado? Observe que a documentação em fluxos paralelos Java não menciona nenhum problema com aninhamento ou sincronização. Além disso, o fato de ambos usarem um pool comum de bifurcação não é mencionado.

Atualizar

Outro teste sobre o problema de desempenho pode ser encontrado emhttp://svn.finmath.net/finmath%20experiments/trunk/src/net/finmath/experiments/concurrency/NestedParallelForEachBenchmark.java - este teste vem sem nenhuma operação de bloqueio (sem Thread.sleep e não sincronizado). Eu compilei mais algumas observações aqui:http://christian-fries.de/blog/files/2014-nested-java-8-parallel-foreach.html

Atualização 2

Parece que esse problema e o DEADLOCK mais grave com semáforos foram corrigidos no Java8 u40.

questionAnswers(3)

yourAnswerToTheQuestion