JavaRush /Java blogi /Random-UZ /Java 8 da massivlar ustida parallel amallar - tarjima
billybonce
Daraja
Москва

Java 8 da massivlar ustida parallel amallar - tarjima

Guruhda nashr etilgan
maqolaning tarjimasi
//Java 8 da parallel massiv operatsiyalari //Erik Bruno tomonidan, 2014 yil 25 mart //drdobbs.com/jvm/parallel-array-operations-in-java-8/240166287 //Erik Bruno moliya sektorida va bloglarda ishlaydi veb-sayt uchun Dr. Dobbniki.
Java-ning yangi versiyasi massivlar bilan parallel ravishda o'zaro ishlashni osonlashtiradi - natijada minimal kodlash bilan ishlash sezilarli darajada yaxshilanadi. Endi Oracle Java SE 8 ni chiqarmoqda - bu til nuqtai nazaridan oldinga katta qadamdir. Ushbu nashrning muhim xususiyatlaridan biri yaxshilangan parallellikdir, ularning ba'zilari java.util.Arrays asosiy sinfida paydo bo'ladi. Ushbu sinfga yangi usullar qo'shildi, men ushbu maqolada tasvirlab beraman. Ulardan ba'zilari JDK8 ning yana bir yangi xususiyati - lambdalarda qo'llaniladi. Ammo keling, biznesga tushaylik.
Arrays.paralellSort()
ParallelSortning koʻpgina funksiyalari massivni rekursiv ravishda qismlarga boʻladigan, saralaydigan va soʻngra ularni bir vaqtning oʻzida yakuniy massivga qayta birlashtiruvchi parallel birlashma tartiblash algoritmiga asoslangan. Mavjud, ketma-ket Arrays.sort usuli o‘rniga undan foydalanish katta massivlarni saralashda unumdorlik va samaradorlikni oshiradi. Misol uchun, quyidagi kod bir xil ma'lumotlar massivini saralash uchun ketma-ket sort() va parallel parallelSort() dan foydalanadi: 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; } } Sinab ko'rish uchun men tasvirdan xom ma'lumotlarni massivga yukladim, u 46 083 360 baytni egalladi (va sizniki tasvirlarga bog'liq bo'ladi). qaysidan foydalanasiz). Mening 4 yadroli noutbukimda massivni saralash uchun ketma-ket tartiblash usuli deyarli 3000 millisekund vaqtni oladi, parallel tartiblash usuli esa ko‘pi bilan 700 millisekundni oladi. Qabul qilaman, tilning yangi yangilanishi sinf samaradorligini 4 baravar oshirishi tez-tez sodir bo'lmaydi.
Arrays.parallelPrefix()
ParallelPrefix usuli ma'lum matematik funktsiyani massiv elementlariga birgalikda qo'llaydi va natijalarni massiv ichidagi parallel ravishda qayta ishlaydi. Bu katta massivlardagi ketma-ket operatsiyalar bilan solishtirganda zamonaviy ko'p yadroli uskunada ancha samarali. Ushbu usulning turli xil asosiy turdagi ma'lumotlar operatsiyalari (masalan, IntBinaryOperator, DoubleBinaryOperator, LongBinaryOperator va boshqalar), shuningdek, har xil turdagi matematik operatorlar uchun ko'plab ilovalari mavjud. Bu mening 4 yadroli noutbukimda taxminan 100 millisekundda yakunlangan oldingi misol kabi bir xil katta massiv yordamida parallel massivlarni stacking misoli. 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 - обработка
Nihoyat, Massivdan siz oqimlar ketma-ketligiga umumlashtirilgan, yaxlit ma'lumotlar namunasiga parallel ishlov berishga imkon beruvchi Stream ob'ektini yaratishingiz mumkin. Ma'lumotlar to'plami va yangi JDK8 dan Stream o'rtasidagi farq shundaki, to'plamlar Stream ishlamasa, elementlar bilan individual ishlash imkonini beradi. Misol uchun, to'plamlar bilan siz elementlarni qo'shishingiz, ularni olib tashlashingiz va o'rtasiga kiritishingiz mumkin. Oqim ketma-ketligi ma'lumotlar to'plamining alohida elementlarini boshqarishga imkon bermaydi, aksincha, butun ma'lumotlarda funktsiyalarni bajarishga imkon beradi. Siz to'plamdan faqat ma'lum qiymatlarni olish (takrorlashlarga e'tibor bermaslik), ma'lumotlarni o'zgartirish operatsiyalari, massivning minimal va maksimalini topish, xaritani qisqartirish funktsiyalari (tarqatilgan hisoblashda qo'llaniladi) va boshqa matematik operatsiyalar kabi foydali operatsiyalarni bajarishingiz mumkin. Quyidagi oddiy misol ma'lumotlar massivini parallel ravishda qayta ishlash va elementlarni yig'ish uchun parallellikdan foydalanadi. public void streamProcessing() { int[] src = getData(); IntStream stream = Arrays.stream(src); int sum = stream.sum(); System.out.println("\nSum: " + sum); }
Xulosa
Java 8, albatta, til uchun eng foydali yangilanishlardan biri bo'ladi. Bu erda eslatib o'tilgan parallel xususiyatlar, lambdalar va boshqa ko'plab kengaytmalar bizning saytimizdagi boshqa Java 8 sharhlari mavzusi bo'ladi.
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION