JavaRush /Blog Java /Random-MS /Operasi selari pada tatasusunan dalam Java 8 - terjemahan...
billybonce
Tahap
Москва

Operasi selari pada tatasusunan dalam Java 8 - terjemahan

Diterbitkan dalam kumpulan
terjemahan artikel
//Operasi Tatasusunan Selari di Java 8 //Oleh Eric Bruno, 25 Mac 2014 //drdobbs.com/jvm/parallel-array-operations-in-java-8/240166287 //Eric Bruno bekerja dalam sektor kewangan dan blog untuk laman web Dr. Dobb's.
Keluaran baharu Java menjadikannya lebih mudah untuk berinteraksi dengan tatasusunan secara selari - menghasilkan prestasi yang dipertingkatkan dengan ketara dengan pengekodan minimum. Kini, Oracle mengeluarkan Java SE 8 - yang merupakan satu langkah besar ke hadapan dari segi bahasa. Salah satu ciri penting keluaran ini ialah konkurensi yang dipertingkatkan, beberapa daripadanya muncul dalam kelas asas java.util.Arrays. Kaedah baharu telah ditambahkan pada kelas ini, yang akan saya huraikan dalam artikel ini. Sebahagian daripada ini digunakan dalam satu lagi ciri baharu JDK8 - lambdas. Tetapi mari kita turun ke perniagaan.
Arrays.paralellSort()
Banyak ciri parallelSort adalah berdasarkan algoritma isihan cantuman selari yang membahagikan tatasusunan secara rekursif kepada bahagian, menyusunnya dan kemudian menggabungkannya semula serentak menjadi tatasusunan akhir. Menggunakannya dan bukannya kaedah Arrays.sort berjujukan sedia ada menghasilkan prestasi dan kecekapan yang lebih baik apabila menyusun tatasusunan yang besar. Sebagai contoh, kod di bawah menggunakan sequential sort() dan parallel parallelSort() untuk mengisih tatasusunan data yang sama: 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; } } Untuk menguji, saya memuatkan data mentah daripada imej ke dalam tatasusunan, yang mengambil 46,083,360 bait (dan anda akan bergantung pada imej yang akan anda gunakan). Kaedah isihan berurutan mengambil masa hampir 3,000 milisaat untuk mengisih tatasusunan pada komputer riba 4 teras saya, manakala kaedah isihan selari mengambil masa paling banyak 700 milisaat. Setuju, ia tidak selalunya berlaku bahawa kemas kini bahasa baharu meningkatkan prestasi kelas sebanyak 4 kali ganda.
Arrays.parallelPrefix()
Kaedah parallelPrefix menggunakan fungsi matematik tertentu kepada elemen tatasusunan secara kolektif, memproses keputusan dalam tatasusunan secara selari. Ini adalah lebih cekap pada perkakasan berbilang teras moden, berbanding dengan operasi berjujukan pada tatasusunan besar. Terdapat banyak pelaksanaan kaedah ini untuk jenis operasi data asas yang berbeza (contohnya, IntBinaryOperator, DoubleBinaryOperator, LongBinaryOperator dan sebagainya), serta untuk pelbagai jenis operator matematik. Berikut ialah contoh susun atur selari menggunakan tatasusunan besar yang sama seperti contoh sebelumnya, yang siap dalam kira-kira 100 milisaat pada komputer riba 4 teras saya. 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 - обработка
Akhir sekali, daripada Array, anda boleh mencipta objek Stream, yang membenarkan pemprosesan selari pada sampel data secara keseluruhan, digeneralisasikan ke dalam urutan aliran. Perbezaan antara Pengumpulan data dan Strim daripada JDK8 baharu ialah koleksi membolehkan anda bekerja dengan elemen secara individu apabila Strim tidak berfungsi. Contohnya, dengan koleksi, anda boleh menambah elemen, mengalih keluarnya dan memasukkannya di tengah. Urutan Strim tidak membenarkan anda memanipulasi elemen individu daripada set data, sebaliknya membenarkan anda melaksanakan fungsi pada data secara keseluruhan. Anda boleh melakukan operasi berguna seperti mengekstrak hanya nilai tertentu (mengabaikan ulangan) daripada set, operasi transformasi data, mencari minimum dan maksimum tatasusunan, fungsi pengurangan peta (digunakan dalam pengkomputeran teragih), dan operasi matematik lain. Contoh mudah berikut menggunakan konkurensi untuk memproses tatasusunan data secara selari dan menjumlahkan elemen. public void streamProcessing() { int[] src = getData(); IntStream stream = Arrays.stream(src); int sum = stream.sum(); System.out.println("\nSum: " + sum); }
Kesimpulan
Java 8 pastinya akan menjadi salah satu kemas kini yang paling berguna kepada bahasa tersebut. Ciri selari yang disebut di sini, lambdas, dan banyak sambungan lain akan menjadi subjek ulasan Java 8 lain di tapak kami.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION