JavaRush /Java Blog /Random-KO /Java 8의 배열에 대한 병렬 작업 - 번역
billybonce
레벨 29
Москва

Java 8의 배열에 대한 병렬 작업 - 번역

Random-KO 그룹에 게시되었습니다
기사 번역
//Java 8의 병렬 배열 작업 //Eric Bruno 작성, 2014년 3월 25일 //drdobbs.com/jvm/parallel-array-Operations-in-java-8/240166287 //Eric Bruno는 금융 부문 및 블로그에서 근무 웹사이트 Dr. 돕스.
새로운 Java 릴리스를 사용하면 배열과 병렬로 상호 작용하는 것이 더 쉬워져 최소한의 코딩으로 성능이 크게 향상됩니다. 이제 오라클은 언어 측면에서 큰 발전을 이룬 Java SE 8을 출시합니다. 이번 릴리스의 중요한 기능 중 하나는 향상된 동시성이며, 그 중 일부는 java.util.Arrays 기본 클래스에 나타납니다. 이 클래스에는 새로운 메서드가 추가되었으며, 이 기사에서는 이에 대해 설명하겠습니다. 이들 중 일부는 JDK8의 또 다른 새로운 기능인 람다에서 사용됩니다. 하지만 사업을 시작합시다.
배열.paralellSort()
ParallelSort의 많은 기능은 배열을 반복적으로 여러 부분으로 분할하고 정렬한 다음 동시에 최종 배열로 재결합하는 병렬 병합 정렬 알고리즘을 기반으로 합니다. 기존의 순차 Arrays.sort 메서드 대신 이를 사용하면 대규모 배열을 정렬할 때 성능과 효율성이 향상됩니다. 예를 들어, 아래 코드는 동일한 데이터 배열을 정렬하기 위해 순차 sort() 및 병렬 parallelSort()를 사용합니다. public class ParallelSort { public static void main(String[] args) { ParallelSort mySort = new ParallelSort(); int[] src = null; System.out.println("\nSerial sort:"); src = mySort.getData(); mySort.sortIt(src, false); System.out.println("\nParallel sort:"); src = mySort.getData(); mySort.sortIt(src, true); } public void sortIt(int[] src, boolean parallel) { try { System.out.println("--Array size: " + src.length); long start = System.currentTimeMillis(); if ( parallel == true ) { Arrays.parallelSort(src); } else { Arrays.sort(src); } long end = System.currentTimeMillis(); System.out.println( "--Elapsed sort time: " + (end-start)); } catch ( Exception e ) { e.printStackTrace(); } } private int[] getData() { try { File file = new File("src/parallelsort/myimage.png"); BufferedImage image = ImageIO.read(file); int w = image.getWidth(); int h = image.getHeight(); int[] src = image.getRGB(0, 0, w, h, null, 0, w); int[] data = new int[src.length * 20]; for ( int i = 0; i < 20; i++ ) { System.arraycopy( src, 0, data, i*src.length, src.length); } return data; } catch ( Exception e ) { e.printStackTrace(); } return null; } } 테스트를 위해 이미지의 원시 데이터를 배열에 로드했는데, 이는 46,083,360바이트를 차지했습니다. (사용자의 데이터는 이미지에 따라 달라집니다.) 당신이 사용할 것입니다). 4코어 노트북에서 배열을 정렬하는 데 순차 정렬 방법은 거의 3,000밀리초가 걸렸고, 병렬 정렬 방법은 최대 약 700밀리초가 걸렸습니다. 동의하세요. 새로운 언어 업데이트로 수업 성과가 4배 향상되는 경우는 자주 발생하지 않습니다.
배열.parallelPrefix()
parallelPrefix 메소드는 지정된 수학 함수를 배열 요소에 집합적으로 적용하여 배열 내의 결과를 병렬로 처리합니다. 이는 대규모 어레이의 순차 작업에 비해 최신 멀티 코어 하드웨어에서 훨씬 더 효율적입니다. 다양한 기본 유형의 데이터 작업(예: IntBinaryOperator, DoubleBinaryOperator, LongBinaryOperator 등)과 다양한 유형의 수학 연산자에 대해 이 메서드를 구현하는 방법이 많이 있습니다. 다음은 이전 예와 동일한 대형 어레이를 사용한 병렬 어레이 스태킹의 예입니다. 이 작업은 4코어 노트북에서 약 100밀리초 만에 완료되었습니다. public class MyIntOperator implements IntBinaryOperator { @Override public int applyAsInt(int left, int right) { return left+right; } } public void accumulate() { int[] src = null; // accumulate test System.out.println("\nParallel prefix:"); src = getData(); IntBinaryOperator op = new ParallelSort.MyIntOperator(); long start = System.currentTimeMillis(); Arrays.parallelPrefix(src, new MyIntOperator()); long end = System.currentTimeMillis(); System.out.println("--Elapsed sort time: " + (end-start)); } ... }
배열.parallelSetAll()
새로운 parallelSetAll() 메서드는 효율성을 높이기 위해 병렬성을 사용하여 배열을 생성하고 해당 값을 생성한 함수에 따라 각 배열 요소를 값으로 설정합니다. 이 방법은 람다(다른 언어에서는 "클로저"라고 함)를 기반으로 합니다. (그렇습니다. 람다와 클로저는 다르기 때문에 이것은 작성자의 실수입니다.) , 이는 향후 기사에서 논의할 JDK8의 또 다른 새로운 기능입니다. -> 연산자로 구문을 쉽게 인식할 수 있는 람다는 전달된 모든 요소에 대해 화살표 뒤 오른쪽에서 작업을 수행한다는 점만 알아두면 충분합니다. 아래 코드 예제에서는 i로 인덱스된 배열의 각 요소에 대해 작업이 수행됩니다. Array.parallelSetAll()은 배열 요소를 생성합니다. 예를 들어 다음 코드는 임의의 정수 값으로 큰 배열을 채웁니다. public void createLargeArray() { Integer[] array = new Integer[1024*1024*4]; // 4M Arrays.parallelSetAll( array, i -> new Integer( new Random().nextInt())); } 보다 복잡한 배열 요소 생성기(예: 실제 센서의 판독값을 기반으로 값을 생성하는 생성기)를 생성하려면 다음과 유사한 코드를 사용할 수 있습니다. 다음은 public void createLargeArray() { Integer[] array = new Integer[1024*1024*4]; // 4M Arrays.parallelSetAll( array, i -> new Integer( customGenerator(getNextSensorValue()))); } public int customGenerator(int arg){ return arg + 1; // some fancy formula here... } public int getNextSensorValue() { // Just random for illustration return new Random().nextInt(); } getNextSensorValue부터 시작하겠습니다. 실제로는 센서(예: 온도계)에 현재 값을 반환하도록 요청합니다. 여기서는 예를 들어 임의의 값이 생성됩니다. 다음 customGenerator() 메서드는 선택한 사례에 따라 선택한 논리를 사용하여 요소 배열을 생성합니다. 여기에 약간의 추가 사항이 있지만 실제 경우에는 더 복잡해집니다.
분할기란 무엇입니까?
동시성과 람다를 활용하는 Arrays 클래스에 추가된 또 다른 기능은 배열을 반복하고 분할하는 데 사용되는 Spliterator입니다. 그 효과는 배열에만 국한되지 않고 컬렉션 클래스 및 IO 채널에도 잘 작동합니다. 분할기는 자동으로 배열을 여러 부분으로 분할하는 방식으로 작동하며, 연결된 하위 배열에 대한 작업을 수행하기 위해 새로운 분할기가 설치됩니다. 그 이름은 이동 반복 작업을 여러 부분으로 "분할"하는 Iterator로 구성됩니다. 동일한 데이터를 사용하여 다음과 같이 어레이에서 분할된 작업을 수행할 수 있습니다. 이러한 방식으로 데이터에 대한 작업을 수행하면 병렬성을 활용합니다. 각 하위 배열의 최소 크기와 같은 분할 매개변수를 설정할 수도 있습니다. public void spliterate() { System.out.println("\nSpliterate:"); int[] src = getData(); Spliterator spliterator = Arrays.spliterator(src); spliterator.forEachRemaining( n -> action(n) ); } public void action(int value) { System.out.println("value:"+value); // Perform some real work on this data here... }
스트림 - 처리
마지막으로 배열에서 스트림 개체를 생성할 수 있습니다. 이 개체를 사용하면 전체 데이터 샘플에 대한 병렬 처리를 허용하고 스트림 시퀀스로 일반화할 수 있습니다. 데이터 컬렉션과 새로운 JDK8의 스트림 사이의 차이점은 스트림이 그렇지 않은 경우에도 컬렉션을 사용하면 요소를 개별적으로 작업할 수 있다는 것입니다. 예를 들어 컬렉션을 사용하면 요소를 추가하고 제거하고 중간에 삽입할 수 있습니다. 스트림 시퀀스를 사용하면 데이터 세트의 개별 요소를 조작할 수 없지만 대신 데이터 전체에 대한 기능을 수행할 수 있습니다. 집합에서 특정 값만 추출(반복 무시), 데이터 변환 작업, 배열의 최소값과 최대값 찾기, 맵 축소 함수(분산 컴퓨팅에 사용됨) 및 기타 수학 연산과 같은 유용한 작업을 수행할 수 있습니다. 다음의 간단한 예에서는 동시성을 사용하여 데이터 배열을 병렬로 처리하고 요소를 합산합니다. public void streamProcessing() { int[] src = getData(); IntStream stream = Arrays.stream(src); int sum = stream.sum(); System.out.println("\nSum: " + sum); }
결론
Java 8은 확실히 언어에 대한 가장 유용한 업데이트 중 하나가 될 것입니다. 여기에 언급된 병렬 기능, 람다 및 기타 여러 확장 기능은 우리 사이트의 다른 Java 8 리뷰의 주제가 될 것입니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION