AtomicInteger recordNumber = new AtomicInteger();
Files.lines(inputFile.toPath(), StandardCharsets.UTF_8)
.map(record -> new Record(recordNumber.incrementAndGet(), record))
.parallel()
.filter(record -> doSomeOperation())
.findFirst()
Quando escrevi isso, assumi que os threads seriam gerados apenas na chamada do mapa, pois o paralelo é colocado após o mapa. Mas algumas linhas no arquivo estavam recebendo números de registros diferentes para cada execução.
Li a documentação oficial do fluxo Java e alguns sites para entender como os fluxos funcionam sob o capô.
Algumas questões:
O fluxo paralelo de Java funciona com base no SplitIterator , que é implementado por todas as coleções como ArrayList, LinkedList etc. Quando construímos um fluxo paralelo a partir dessas coleções, o iterador de divisão correspondente será usado para dividir e iterar a coleção. Isso explica por que o paralelismo aconteceu no nível da fonte de entrada original (linhas de arquivo) e não no resultado do mapa (ou seja, Record pojo). Meu entendimento está correto?
No meu caso, a entrada é um fluxo de E / S de arquivo. Qual iterador dividido será usado?
Não importa onde colocamos
parallel()
no pipeline. A fonte de entrada original será sempre dividida e as operações intermediárias restantes serão aplicadas.Nesse caso, o Java não deve permitir que os usuários coloquem operações paralelas em qualquer lugar do pipeline, exceto na fonte original. Porque está dando um entendimento errado para quem não sabe como o java stream funciona internamente. Eu sei que a
parallel()
operação teria sido definida para o tipo de objeto Stream e, portanto, está funcionando dessa maneira. Mas, é melhor fornecer uma solução alternativa.No trecho de código acima, estou tentando adicionar um número de linha a cada registro no arquivo de entrada e, portanto, ele deve ser solicitado. No entanto, quero aplicar
doSomeOperation()
em paralelo, pois é uma lógica de peso pesado. A única maneira de conseguir é escrever meu próprio iterador dividido personalizado. Existe alguma outra maneira?
Stream
diretamente na interface e, devido à boa cascata, todas as operações são devolvidas Stream
. Imagine que alguém queira lhe dar uma, Stream
mas já aplicou algumas operações semelhantes map
a ela. Você, como usuário, ainda deseja decidir se deve executá-lo em paralelo ou não. Portanto, você deve poder ligar parallel()
ainda, embora o fluxo já exista.
flatMap
ou se executasse métodos inseguros ou similares.
Path
estiver no sistema de arquivos local e você estiver usando um JDK recente, o spliterator terá uma capacidade de processamento paralelo melhor do que múltiplos em lotes de 1024. Mas a divisão equilibrada pode até ser contraproducente em alguns findFirst
cenários ...
parallel()
nada mais é do que uma solicitação geral de modificador aplicada ao objeto de fluxo subjacente. Lembre-se de que existe apenas um fluxo de origem se você não aplicar operações finais ao canal, ou seja, desde que nada seja "executado". Dito isto, você está basicamente questionando as opções de design do Java. Qual é a opinião e não podemos realmente ajudar com isso.