JavaRush /Java Blog /Random-TL /Mga parallel na operasyon sa mga array sa Java 8 - pagsas...
billybonce
Antas
Москва

Mga parallel na operasyon sa mga array sa Java 8 - pagsasalin

Nai-publish sa grupo
pagsasalin ng artikulo
//Parallel Array Operations in Java 8 //Ni Eric Bruno, Marso 25, 2014 //drdobbs.com/jvm/parallel-array-operations-in-java-8/240166287 //Gumagana si Eric Bruno sa sektor ng pananalapi at mga blog para sa website na Dr. kay Dobb.
Pinapadali ng bagong release ng Java ang pakikipag-ugnayan sa mga arrays nang magkatulad - na nagreresulta sa makabuluhang pinahusay na pagganap na may minimum na coding. Ngayon, ang Oracle ay naglalabas ng Java SE 8 - na isang malaking hakbang pasulong sa mga tuntunin ng wika. Ang isa sa mga mahalagang tampok ng release na ito ay pinahusay na concurrency, ang ilan ay lumalabas sa java.util.Arrays base class. Ang mga bagong pamamaraan ay naidagdag sa klase na ito, na ilalarawan ko sa artikulong ito. Ang ilan sa mga ito ay ginagamit sa isa pang bagong tampok ng JDK8 - lambdas. Ngunit bumaba tayo sa negosyo.
Arrays.paralellSort()
Marami sa mga feature ng parallelSort ay batay sa isang parallel merge sort algorithm na paulit-ulit na hinahati ang isang array sa mga bahagi, pinagbubukod-bukod ang mga ito, at pagkatapos ay muling pinagsama-sama ang mga ito nang sabay-sabay sa isang huling array. Ang paggamit nito sa halip na ang umiiral na, sequential Arrays.sort method ay nagreresulta sa pinahusay na performance at kahusayan kapag nag-uuri ng malalaking array. Halimbawa, ang code sa ibaba ay gumagamit ng sequential sort() at parallel parallelSort() para pag-uri-uriin ang parehong array ng data: 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; } } Upang subukan, ni-load ko ang raw data mula sa imahe papunta sa array, na kumuha ng 46,083,360 bytes (at ang sa iyo ay depende sa mga larawan na iyong gagamitin). Ang sunud-sunod na paraan ng pag-uuri ay tumagal ng halos 3,000 millisecond upang pag-uri-uriin ang array sa aking 4-core na laptop, habang ang parallel sort na paraan ay tumagal ng humigit-kumulang 700 milliseconds. Sumang-ayon, hindi madalas na nangyayari na ang isang bagong pag-update ng wika ay nagpapabuti sa pagganap ng klase nang 4 na beses.
Arrays.parallelPrefix()
Ang parallelPrefix method ay naglalapat ng isang tinukoy na mathematical function sa mga elemento ng isang array nang sama-sama, pinoproseso ang mga resulta sa loob ng array nang magkatulad. Ito ay mas mahusay sa modernong multi-core na hardware, kumpara sa mga sunud-sunod na operasyon sa malalaking array. Maraming mga pagpapatupad ng paraang ito para sa iba't ibang pangunahing uri ng mga pagpapatakbo ng data (halimbawa, IntBinaryOperator, DoubleBinaryOperator, LongBinaryOperator, at iba pa), pati na rin para sa iba't ibang uri ng mga mathematical operator. Narito ang isang halimbawa ng parallel array stacking gamit ang parehong malaking array gaya ng nakaraang halimbawa, na nakumpleto sa humigit-kumulang 100 milliseconds sa aking 4-core na laptop. 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 - обработка
Sa wakas, mula sa isang Array, maaari kang lumikha ng isang Stream object, na nagbibigay-daan sa parallel processing sa isang sample ng data sa kabuuan, na pangkalahatan sa isang stream sequence. Ang pagkakaiba sa pagitan ng isang Koleksyon ng data at isang Stream mula sa bagong JDK8 ay ang mga koleksyon ay nagbibigay-daan sa iyong magtrabaho sa mga elemento nang paisa-isa kapag ang isang Stream ay hindi. Halimbawa, sa mga koleksyon, maaari kang magdagdag ng mga elemento, alisin ang mga ito, at ipasok ang mga ito sa gitna. Ang isang Stream sequence ay hindi nagpapahintulot sa iyo na manipulahin ang mga indibidwal na elemento mula sa isang set ng data, ngunit sa halip ay nagbibigay-daan sa iyong magsagawa ng mga function sa data sa kabuuan. Maaari kang magsagawa ng mga kapaki-pakinabang na operasyon tulad ng pagkuha lamang ng mga partikular na halaga (hindi pinapansin ang mga pag-uulit) mula sa isang set, mga operasyon sa pagbabago ng data, paghahanap ng minimum at maximum ng isang array, mapa-reduce na mga function (ginagamit sa distributed computing), at iba pang mga mathematical operations. Ang sumusunod na simpleng halimbawa ay gumagamit ng concurrency upang iproseso ang isang hanay ng data nang magkatulad at isama ang mga elemento. public void streamProcessing() { int[] src = getData(); IntStream stream = Arrays.stream(src); int sum = stream.sum(); System.out.println("\nSum: " + sum); }
Konklusyon
Ang Java 8 ay tiyak na magiging isa sa mga pinakakapaki-pakinabang na update sa wika. Ang mga parallel na feature na binanggit dito, lambdas, at marami pang ibang extension ay magiging paksa ng iba pang Java 8 review sa aming site.
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION