AtomicInteger recordNumber = new AtomicInteger();
Files.lines(inputFile.toPath(), StandardCharsets.UTF_8)
.map(record -> new Record(recordNumber.incrementAndGet(), record))
.parallel()
.filter(record -> doSomeOperation())
.findFirst()
이 글을 쓰면 맵 뒤에 병렬이 배치되므로 스레드가 맵 호출 만 생성된다고 가정했습니다. 그러나 파일의 일부 줄은 매 실행마다 다른 레코드 번호를 얻었습니다.
공식 Java 스트림 설명서 와 몇 가지 웹 사이트를 읽고 스트림에서 스트림이 작동하는 방식을 이해합니다.
몇 가지 질문 :
Java 병렬 스트림은 ArrayList, LinkedList 등의 모든 컬렉션에 의해 구현되는 SplitIterator를 기반으로 작동 합니다. 컬렉션에서 병렬 스트림을 구성 할 때 해당 분할 반복자는 컬렉션을 분할하고 반복하는 데 사용됩니다. 이것은 맵 결과 (예 : 레코드 포조)가 아닌 원래 입력 소스 (파일 라인) 레벨에서 병렬 처리가 발생한 이유를 설명합니다. 내 이해가 정확합니까?
필자의 경우 입력은 파일 IO 스트림입니다. 어떤 분할 반복기가 사용됩니까?
parallel()
파이프 라인에서 어디에 배치하든 문제가되지 않습니다 . 원래 입력 소스는 항상 분리되고 나머지 중간 작업이 적용됩니다.이 경우 Java는 사용자가 원본 소스를 제외하고 파이프 라인의 어느 곳에 나 병렬 작업을 배치 할 수 없도록해야합니다. Java 스트림이 내부에서 어떻게 작동하는지 모르는 사람들에게는 잘못 이해하고 있기 때문입니다.
parallel()
Stream 객체 유형에 대해 작업이 정의되었을 것이므로 이러한 방식으로 작동합니다. 그러나 대체 솔루션을 제공하는 것이 좋습니다.위의 코드 스 니펫에서 입력 파일의 모든 레코드에 줄 번호를 추가하려고하므로 순서를 지정해야합니다. 그러나
doSomeOperation()
무거운 논리이기 때문에 병렬로 적용하고 싶습니다 . 달성하는 한 가지 방법은 나만의 맞춤형 분할 반복자를 작성하는 것입니다. 다른 방법이 있습니까?
Stream
인터페이스에서 직접 제공되며 멋진 계단식으로 인해 모든 작업이 다시 제공 Stream
됩니다. 누군가가 당신에게주고 Stream
싶지만 이미 이와 비슷한 몇 가지 작업을 적용 했다고 상상해보십시오 map
. 사용자는 여전히 병렬로 실행할지 여부를 결정할 수 있습니다. 따라서 parallel()
스트림이 이미 존재하더라도 여전히 전화를 걸 수 있어야 합니다.
flatMap
스레드 안전하지 않은 메소드를 사용하거나 이와 유사한 방식으로 크기를 크게 늘리 거나 같은 경우가 있습니다 .
Path
이 로컬 파일 시스템에 있고 최근 JDK를 사용하는 경우 스플리터는 1024의 배수를 일괄 처리하는 것보다 더 나은 병렬 처리 기능을 갖습니다. 그러나 일부 findFirst
시나리오 에서는 균형 잡힌 분할이 반 생산적 일 수도 있습니다 .
parallel()
기본 스트림 객체에 적용되는 일반적인 수정 자 요청에 지나지 않습니다. 파이프에 최종 작업을 적용하지 않는 경우, 즉 "실행 된"항목이없는 한 소스 스트림이 하나만 있어야합니다. 말했듯이, 당신은 기본적으로 Java 디자인 선택에 의문을 품고 있습니다. 그것은 의견에 근거한 것이며 우리는 실제로 그것을 도울 수 없습니다.