JavaRush /Блоги Java /Random-TG /Амалиёти параллелӣ дар массивҳо дар Java 8 - тарҷума
billybonce
Сатҳи
Москва

Амалиёти параллелӣ дар массивҳо дар Java 8 - тарҷума

Дар гурӯҳ нашр шудааст
тарҷумаи мақола
//Амалиёти массивҳои параллелӣ дар Java 8 //Аз ҷониби Эрик Бруно, 25 марти 2014 //drdobbs.com/jvm/parallel-array-operations-in-java-8/240166287 //Эрик Бруно дар бахши молиявӣ ва блогҳо кор мекунад барои вебсайти Dr. Добб.
Нашри нави Java муоширатро бо массивҳо дар баробари осонтар мекунад - дар натиҷа иҷрои хеле беҳтар бо ҳадди ақали рамзгузорӣ. Ҳоло Oracle Java SE 8-ро мебарорад, ки ин як қадами бузурге ба пеш дар робита ба забон аст. Яке аз вижагиҳои муҳими ин versionи мукаммалгардонии ҳамзамон аст, ки баъзеи онҳо дар синфи пойгоҳи java.util.Arrays пайдо мешаванд. Ба ин синф усулҳои нав илова карда шуданд, ки ман дар ин мақола тавсиф мекунам. Баъзе аз онҳо дар дигар хусусияти нави JDK8 - lambdas истифода мешаванд. Аммо биёед ба коре равем.
Arrays.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 byteро дар бар мегирад (ва аз они шумо аз тасвирҳо вобаста хоҳад буд) ки шумо истифода мебаред). Усули навъбандии пайдарпай барои ҷудо кардани массив дар ноутбуки 4-аслии ман тақрибан 3000 миллисония вақтро сарф кард, дар ҳоле ки усули навъбандии параллелӣ ҳадди аксар тақрибан 700 миллисонияро мегирад. Розӣ шавед, аксар вақт рӯй намедиҳад, ки навсозии забони нав кори синфро 4 маротиба беҳтар мекунад.
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.
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION