JavaRush /Java Blogu /Random-AZ /Java 8-də massivlər üzərində paralel əməliyyatlar - tərcü...
billybonce
Səviyyə
Москва

Java 8-də massivlər üzərində paralel əməliyyatlar - tərcümə

Qrupda dərc edilmişdir
məqalənin tərcüməsi
//Java 8-də Paralel Massiv Əməliyyatları //Erik Bruno tərəfindən, 25 mart 2014-cü il //drdobbs.com/jvm/parallel-array-operations-in-java-8/240166287 //Erik Bruno maliyyə sektorunda və bloqlarda işləyir vebsayt üçün Dr. Dobbun.
Java-nın yeni buraxılışı massivlərlə paralel olaraq qarşılıqlı əlaqəni asanlaşdırır - nəticədə minimum kodlaşdırma ilə performansı əhəmiyyətli dərəcədə yaxşılaşdırır. İndi Oracle Java SE 8-i buraxır - bu dil baxımından irəliyə doğru böyük bir addımdır. Bu buraxılışın mühüm xüsusiyyətlərindən biri təkmilləşdirilmiş paralellikdir, onlardan bəziləri java.util.Arrays baza sinfində görünür. Bu yazıda təsvir edəcəyəm bu sinfə yeni üsullar əlavə edildi. Bunlardan bəziləri JDK8-in başqa bir yeni xüsusiyyətində - lambdalarda istifadə olunur. Amma gəlin işə başlayaq.
Arrays.paralellSort()
ParalelSort funksiyalarının bir çoxu massivi rekursiv şəkildə hissələrə ayıran, çeşidləyən və sonra eyni vaxtda yekun massivdə birləşdirən paralel birləşmə çeşidləmə alqoritminə əsaslanır. Mövcud, ardıcıl Arrays.sort metodu əvəzinə ondan istifadə böyük massivləri çeşidləyərkən təkmilləşdirilmiş performans və səmərəliliklə nəticələnir. Məsələn, aşağıdakı kod eyni məlumat massivini çeşidləmək üçün ardıcıl sort() və paralel parallelSort() funksiyalarından istifadə edir: 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; } } Test etmək üçün mən təsvirdən 46,083,360 bayt tutmuş (və sizinki şəkillərdən asılı olacaq) massivə xam verilənləri yüklədim. istifadə edəcəksiniz). Ardıcıl çeşidləmə metodu mənim 4 nüvəli noutbukumda massivi çeşidləmək üçün demək olar ki, 3000 millisaniyə çəkdi, paralel çeşidləmə üsulu isə ən çoxu təxminən 700 millisaniyə çəkdi. Razılaşın, tez-tez baş vermir ki, yeni dil yeniləməsi sinif performansını 4 dəfə yaxşılaşdırır.
Arrays.parallelPrefix()
ParalelPrefiks metodu massivin elementlərinə kollektiv şəkildə müəyyən edilmiş riyazi funksiyanı tətbiq edir, massiv daxilində nəticələri paralel şəkildə emal edir. Bu, böyük massivlərdə ardıcıl əməliyyatlarla müqayisədə müasir çoxnüvəli aparatlarda daha səmərəlidir. Bu metodun müxtəlif əsas tipli verilənlər əməliyyatları üçün (məsələn, IntBinaryOperator, DoubleBinaryOperator, LongBinaryOperator və s.), eləcə də müxtəlif növ riyazi operatorlar üçün bir çox tətbiqi mövcuddur. Budur, mənim 4 nüvəli noutbukumda təxminən 100 millisaniyə ərzində tamamlanan əvvəlki nümunə ilə eyni böyük massivdən istifadə edərək paralel massiv yığma nümunəsi. 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 - обработка
Nəhayət, Massivdən axın ardıcıllığına ümumiləşdirilmiş bütövlükdə verilənlər nümunəsi üzrə paralel emal etməyə imkan verən Stream obyekti yarada bilərsiniz. Məlumat Kolleksiyası ilə yeni JDK8-dən Axın arasındakı fərq ondan ibarətdir ki, axın ardıcıllığı işləmədikdə kolleksiyalar sizə elementlərlə fərdi işləməyə imkan verir. Məsələn, kolleksiyalarla elementləri əlavə edə, silə və ortasına daxil edə bilərsiniz. Axın ardıcıllığı sizə məlumat dəstindən ayrı-ayrı elementləri manipulyasiya etməyə imkan vermir, əksinə bütövlükdə verilənlər üzərində funksiyaları yerinə yetirməyə imkan verir. Siz çoxluqdan yalnız xüsusi dəyərlərin çıxarılması (təkrarlara məhəl qoymamaq), məlumatların çevrilməsi əməliyyatları, massivin minimum və maksimumunun tapılması, xəritəni azaltma funksiyaları (paylanmış hesablamalarda istifadə olunur) və digər riyazi əməliyyatlar kimi faydalı əməliyyatları yerinə yetirə bilərsiniz. Aşağıdakı sadə misal paralel olaraq verilənlər massivini emal etmək və elementləri cəmləmək üçün paralellikdən istifadə edir. public void streamProcessing() { int[] src = getData(); IntStream stream = Arrays.stream(src); int sum = stream.sum(); System.out.println("\nSum: " + sum); }
Nəticə
Java 8 mütləq dil üçün ən faydalı yeniləmələrdən biri olacaq. Burada qeyd olunan paralel xüsusiyyətlər, lambdalar və bir çox digər uzantılar saytımızdakı digər Java 8 baxışlarının mövzusu olacaq.
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION