JavaRush /Java Blog /Random-ID /Operasi paralel pada array di Java 8 - terjemahan
billybonce
Level 29
Москва

Operasi paralel pada array di Java 8 - terjemahan

Dipublikasikan di grup Random-ID
terjemahan artikel
//Operasi Array Paralel di Java 8 //Oleh Eric Bruno, 25 Maret 2014 //drdobbs.com/jvm/parallel-array-operations-in-java-8/240166287 //Eric Bruno bekerja di sektor keuangan dan blog untuk situs web Dr. milik Dobb.
Rilis baru Java mempermudah interaksi dengan array secara paralel - menghasilkan peningkatan kinerja yang signifikan dengan pengkodean minimum. Kini, Oracle merilis Java SE 8 - yang merupakan langkah maju yang besar dalam hal bahasa. Salah satu fitur penting dari rilis ini adalah peningkatan konkurensi, beberapa di antaranya muncul di kelas dasar java.util.Arrays. Metode baru telah ditambahkan ke kelas ini, yang akan saya jelaskan di artikel ini. Beberapa di antaranya digunakan dalam fitur baru JDK8 lainnya - lambda. Tapi mari kita mulai berbisnis.
Array.paralellSort()
Banyak fitur parallelSort didasarkan pada algoritma pengurutan gabungan paralel yang secara rekursif membagi array menjadi beberapa bagian, mengurutkannya, dan kemudian menggabungkannya kembali secara bersamaan menjadi array akhir. Menggunakannya sebagai pengganti metode Arrays.sort berurutan yang sudah ada akan menghasilkan peningkatan kinerja dan efisiensi saat mengurutkan array besar. Misalnya, kode di bawah ini menggunakan sequence sort() dan parallelSort() untuk mengurutkan array 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 mengujinya, saya memuat data mentah dari gambar ke dalam array, yang membutuhkan 46.083.360 byte (dan data Anda akan bergantung pada gambar yang akan Anda gunakan). Metode pengurutan sekuensial memerlukan waktu hampir 3.000 milidetik untuk mengurutkan array di laptop 4-core saya, sedangkan metode pengurutan paralel memerlukan waktu paling lama sekitar 700 milidetik. Setuju, tidak sering pembaruan bahasa baru meningkatkan kinerja kelas sebanyak 4 kali lipat.
Array.parallelPrefix()
Metode parallelPrefix menerapkan fungsi matematika tertentu ke elemen array secara kolektif, memproses hasil dalam array secara paralel. Ini jauh lebih efisien pada perangkat keras multi-core modern, dibandingkan dengan operasi sekuensial pada array besar. Ada banyak implementasi metode ini untuk berbagai tipe dasar operasi data (misalnya, IntBinaryOperator, DoubleBinaryOperator, LongBinaryOperator, dan sebagainya), serta untuk berbagai jenis operator matematika. Berikut adalah contoh penumpukan array paralel menggunakan array besar yang sama seperti contoh sebelumnya, yang selesai dalam waktu sekitar 100 milidetik pada laptop 4-core 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)); } ... }
Array.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 - обработка
Terakhir, dari Array, Anda dapat membuat objek Stream, yang memungkinkan pemrosesan paralel pada sampel data secara keseluruhan, digeneralisasikan ke dalam urutan aliran. Perbedaan antara Kumpulan data dan Aliran dari JDK8 baru adalah bahwa koleksi memungkinkan Anda bekerja dengan elemen secara individual ketika Aliran tidak. Misalnya, dengan koleksi, Anda dapat menambahkan elemen, menghapusnya, dan menyisipkannya di tengah. Urutan aliran tidak memungkinkan Anda memanipulasi elemen individual dari kumpulan data, namun memungkinkan Anda menjalankan fungsi pada data secara keseluruhan. Anda dapat melakukan operasi berguna seperti mengekstraksi hanya nilai tertentu (mengabaikan pengulangan) dari suatu kumpulan, operasi transformasi data, mencari nilai minimum dan maksimum dari sebuah array, fungsi pengurangan peta (digunakan dalam komputasi terdistribusi), dan operasi matematika lainnya. Contoh sederhana berikut ini menggunakan konkurensi untuk memproses array data secara paralel dan menjumlahkan elemennya. public void streamProcessing() { int[] src = getData(); IntStream stream = Arrays.stream(src); int sum = stream.sum(); System.out.println("\nSum: " + sum); }
Kesimpulan
Java 8 pasti akan menjadi salah satu pembaruan bahasa yang paling berguna. Fitur paralel yang disebutkan di sini, lambda, dan banyak ekstensi lainnya akan menjadi subjek ulasan Java 8 lainnya di situs kami.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION