JavaRush /Java Blog /Random-TK /Java 8-de massiwlerde parallel amallar - terjime
billybonce
Dereje
Москва

Java 8-de massiwlerde parallel amallar - terjime

Toparda çap edildi
makalanyň terjimesi
// Java 8-de parallel Array amallary // Erik Bruno tarapyndan 2014-nji ýylyň 25-nji marty //drdobbs.com/jvm/parallel-array-operations-in-java-8/240166287 // Erik Bruno maliýe pudagynda we bloglarda işleýär web sahypasy üçin Dr. Dobb's.
Java-yň täze çykmagy, massiwler bilen paralel täsirleşmegi aňsatlaşdyrýar - iň az kodlaşdyrmak bilen öndürijiligi ep-esli gowulaşdyrýar. Indi “Oracle” Java SE 8-ni çykarýar - bu dil taýdan ägirt ädimdir. Bu goýberilişiň möhüm aýratynlyklaryndan biri java.util.Arrays esasy synpynda peýda bolan sazlaşyklylygy gowulandyrmakdyr. Bu klasa täze usullar goşuldy, bu makalada beýan ederin. Bularyň käbiri JDK8-iň başga bir aýratynlygy - lambdalarda ulanylýar. Let'söne geliň, işe gireliň.
Arrays.paralellSort ()
“ParalelSort” -yň aýratynlyklarynyň köpüsi bir massiwiň böleklere bölünýän, olary tertipleşdirýän we şol bir wagtyň özünde soňky massiwde birleşdirýän parallel birleşdiriş sort algoritmine esaslanýar. Bar bolan, yzygiderli “Arrays.sort” usulynyň ýerine ulanmak, uly massiwleri tertiplände öndürijiligiň we netijeliligiň ýokarlanmagyna getirýär. Mysal üçin, aşakdaky kody şol bir maglumat massiwini tertiplemek üçin yzygiderli sort () we parallel parallelSort () ulanýar: 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; } } Synag üçin, suratdaky çig maglumatlary 46,083,360 baýt alýan massiwde ýükledim (we siziňki suratlara bagly bolar) ulanarsyňyz). Yzygiderli sortlamak usuly, 4 ýadroly noutbukdaky massiwleri tertiplemek üçin 3000 millisekunt töweregi wagt aldy, paralel sort usuly bolsa takmynan 700 millisekunt aldy. Razy, täze dil täzelenmesiniň synp işini 4 esse ýokarlandyrmagy köplenç bolup geçmeýär.
Arrays.parallelPrefix ()
Метод parallelPrefix применяет заданную математическую функцию к elementм массива в совокупности, обрабатывая результаты внутри массива параллельно. Это намного более эффективно на современном многоядерном железе, по сравнению с последовательными операциями на больших массивах. Есть много реализаций этого метода для разных базовых типов операций над данными(например IntBinaryOperator, DoubleBinaryOperator, LongBinaryOperator и так далее), также How и для различных типов математических операторов. Приведу пример суммирования с накоплением на параллельном массиве, использующего тот же самый большой массив, How и в предыдущем примере, который завершается примерно за 100 миллисекунд на моём 4х ядерном ноутбуке. 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)); } ... }
Arrays.parallelSetAll()
Новый метод parallelSetAll() создает массив и устанавливает каждому элементу массива meaning в соответствии с генерирующей эти значения функцией, используя параллельность для повышения эфективности. Этот метод основан на лямбдах(называемых "замыканиями"(closures) в других языках) (и, да, тут ошибка автора, ибо лямбды и замыкания это разные вещи) , и которые являются еще одной новинкой JDK8, которую мы обсудим в будущих статьях. Будет достаточно заметить, лямбды, чей синтаксис легко опознать по оператору ->, производящему операцию над правой частью после стрелки для всех переданных ему элементов. В примере codeа, представленном ниже - действие производится для каждого element в массиве, проиндексированного по i. Array.parallelSetAll() генерирует элементы массива. Например, следующий code заполняет большой массив случайными integer-значениями: public void createLargeArray() { Integer[] array = new Integer[1024*1024*4]; // 4M Arrays.parallelSetAll( array, i -> new Integer( new Random().nextInt())); } Для создания более сложного генератора элементов массива(например, такого что генерировал бы значения на основе считывания с датчиков из реального мира), можно использовать code близкий к следующему: 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, который в реальности будет запрашивать датчик(например термометр) вернуть ему текущее meaning. Здесь же для примера генерируется случайное meaning. Следующий customGenerator() метод генерирует массив элементов с использованием выбранной логики на основе выбранного вами случая. Вот небольшое дополнение, но для реальных случаев, тут было бы что-нибудь посложнее.
What такое Spliterator?
Другое дополнение к классу Arrays, которое использует параллельность и лямбды - это Spliterator, который используется для итерации и разделения массива. Его действие не ограничено только массивами - он также хорошо работает и для классов Collection и IO каналов. Spliterator'ы работают на основе автоматического разбиения массива на различные части, а новый Spliterator устанавливается для того чтобы производить операции над этими связанными подмассивами. Его название составленно из Iterator(итератора), который "разделяет"(splits) его работу по перемещению-итерации на части. Используя наши, всё те же, данные, мы можем произвести раздельноитерированное(splititerated) действие над нашим массивом следующим образом: 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... } Выполнение действий над данными таким образом использует плюсы параллельности. Вы можете также задать параметры сплититератора, такие How минимальный размер каждого подмассива.
Stream - обработка
Наконец, из массива(Array), вы можете создавать an object Stream, который позволяет производить параллельную обработку на выборке данных How целом, обобщенном в последовательность-поток(stream). Difference между коллекцией(Collection) данных и последовательностью-потоком(Stream) из новой JDK8 такая что коллекции позволяют работать с elementми по-отдельности, когда How последовательность-поток не позволяет. Например, с использованием коллекций, вы можете добавлять элементы, удалять, и вставлять в середину. Последовательность-поток Stream не позволяет манипулировать отдельными elementми из набора данных, но instead of этого позволяет выполнять функции над данными How одним целом. Вы можете выполнять такие полезные операции How вытащить только конкретные значения(игнорируя повторы) из набора, операции преобразования данных, нахождение минимумов и максимумов массива, функций map-reduce(используются при распределённых вычислениях), и других математических операциях. Следующий простой пример использует concurrency для параллельной обработки массива данных и суммирования элементов. public void streamProcessing() { int[] src = getData(); IntStream stream = Arrays.stream(src); int sum = stream.sum(); System.out.println("\nSum: " + sum); }
Заключение
Java 8 определённо будет одним из самых полезных обновлений языка. Параллельные фичи, упомянутые здесь, лямбды, и множество других расширений, будут предметом рассмотрения на нашем сайте в других обзорах на Java 8.
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION