Dengan Java 8 dan lambdas, mudah untuk mengulangi koleksi sebagai stream, dan juga mudah menggunakan stream paralel. Dua contoh dari dokumen , yang kedua menggunakan parallelStream:
myShapesCollection.stream()
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));
myShapesCollection.parallelStream() // <-- This one uses parallel
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));
Selama saya tidak peduli dengan pesanan, apakah akan selalu bermanfaat untuk menggunakan paralel? Orang akan berpikir lebih cepat membagi pekerjaan pada lebih banyak core.
Apakah ada pertimbangan lain? Kapan aliran paralel digunakan dan kapan non-paralel digunakan?
(Pertanyaan ini diminta untuk memicu diskusi tentang bagaimana dan kapan menggunakan aliran paralel, bukan karena saya pikir selalu menggunakannya adalah ide yang bagus.)
sumber
Runnable
yang saya panggilstart()
untuk menggunakannyaThreads
, apakah boleh mengubah itu menggunakan java 8 stream secara.forEach()
paralel? Maka saya bisa menghapus kode utas dari kelas. Tetapi apakah ada kerugian?Stream API dirancang untuk membuatnya mudah untuk menulis perhitungan dengan cara yang disarikan dari bagaimana mereka akan dieksekusi, membuat beralih antara sekuensial dan paralel menjadi mudah.
Namun, hanya karena mudah, tidak berarti selalu merupakan ide yang bagus, dan pada kenyataannya, itu adalah ide yang buruk untuk drop
.parallel()
seluruh tempat hanya karena Anda bisa.Pertama, perhatikan bahwa paralelisme tidak menawarkan manfaat selain kemungkinan eksekusi lebih cepat ketika lebih banyak core tersedia. Eksekusi paralel akan selalu melibatkan lebih banyak pekerjaan daripada yang berurutan, karena selain menyelesaikan masalah, ia juga harus melakukan pengiriman dan koordinasi sub-tugas. Harapannya adalah Anda akan bisa mendapatkan jawaban lebih cepat dengan memecah pekerjaan di beberapa prosesor; apakah ini benar-benar terjadi tergantung pada banyak hal, termasuk ukuran kumpulan data Anda, berapa banyak perhitungan yang Anda lakukan pada setiap elemen, sifat perhitungan (khususnya, apakah pemrosesan satu elemen berinteraksi dengan pemrosesan yang lain?) , jumlah prosesor yang tersedia, dan jumlah tugas lain yang bersaing untuk prosesor tersebut.
Lebih lanjut, perhatikan bahwa paralelisme juga sering memperlihatkan nondeterminisme dalam perhitungan yang sering disembunyikan oleh implementasi berurutan; kadang-kadang ini tidak masalah, atau dapat dikurangi dengan membatasi operasi yang terlibat (yaitu, operator reduksi harus stateless dan asosiatif.)
Pada kenyataannya, terkadang paralelisme akan mempercepat perhitungan Anda, terkadang tidak, dan terkadang bahkan memperlambatnya. Yang terbaik adalah mengembangkan terlebih dahulu menggunakan eksekusi berurutan dan kemudian menerapkan paralelisme di mana
(A) Anda tahu bahwa sebenarnya ada manfaat untuk peningkatan kinerja dan
(B) bahwa itu benar-benar akan memberikan peningkatan kinerja.
(A) adalah masalah bisnis, bukan masalah teknis. Jika Anda seorang ahli kinerja, Anda biasanya dapat melihat kode dan menentukan (B), tetapi jalur pintar untuk mengukur. (Dan, jangan repot-repot sampai Anda yakin (A); jika kodenya cukup cepat, lebih baik untuk menerapkan siklus otak Anda di tempat lain.)
Model kinerja paling sederhana untuk paralelisme adalah model "NQ", di mana N adalah jumlah elemen, dan Q adalah perhitungan per elemen. Secara umum, Anda memerlukan produk NQ untuk melebihi ambang batas sebelum Anda mulai mendapatkan manfaat kinerja. Untuk masalah Q rendah seperti "tambahkan angka dari 1 ke N", Anda biasanya akan melihat titik impas antara N = 1000 dan N = 10.000. Dengan masalah Q yang lebih tinggi, Anda akan melihat breakevens di ambang yang lebih rendah.
Tetapi kenyataannya cukup rumit. Jadi sampai Anda mencapai keahlian, pertama-tama kenali kapan pemrosesan sekuensial benar-benar merugikan Anda, dan kemudian ukur apakah paralelisme akan membantu.
sumber
findAny
alih-alihfindFirst
...myListOfURLs.stream().map((url) -> downloadPage(url))...
).ForkJoinPool.commonPool()
dan Anda tidak ingin memblokir tugas untuk pergi ke sana.Aku melihat salah satu presentasi dari Brian Goetz (Bahasa Jawa Arsitek & spesifikasi memimpin untuk Ekspresi Lambda) . Dia menjelaskan secara rinci 4 poin berikut untuk dipertimbangkan sebelum pergi untuk paralelisasi:
Biaya pemisahan / penguraian
- Kadang-kadang pemisahan lebih mahal daripada hanya melakukan pekerjaan!
Pengiriman
tugas / biaya manajemen - Dapat melakukan banyak pekerjaan dalam waktu yang diperlukan untuk menyerahkan pekerjaan ke utas lainnya.
Biaya kombinasi hasil
- Kadang kombinasi melibatkan penyalinan banyak data. Misalnya, menambahkan angka itu murah sedangkan menggabungkan set itu mahal.
Lokalitas
- Gajah di dalam ruangan. Ini adalah poin penting yang mungkin dilewatkan semua orang. Anda harus mempertimbangkan kesalahan cache, jika CPU menunggu data karena cache hilang, maka Anda tidak akan mendapatkan apa pun dengan paralelisasi. Itu sebabnya sumber berbasis array memparalelkan yang terbaik sebagai indeks berikutnya (dekat indeks saat ini) di-cache dan ada sedikit kemungkinan bahwa CPU akan mengalami cache miss.
Dia juga menyebutkan formula yang relatif sederhana untuk menentukan peluang percepatan paralel.
Model NQ :
di mana,
N = jumlah item data
Q = jumlah pekerjaan per item
sumber
JB memukul kepala. Satu-satunya hal yang dapat saya tambahkan adalah bahwa Java 8 tidak melakukan pemrosesan paralel murni, itu tidak parsial . Ya saya menulis artikel dan saya sudah melakukan F / J selama tiga puluh tahun jadi saya mengerti masalah ini.
sumber
ArrayList
/HashMap
.Jawaban lain telah mencakup pembuatan profil untuk menghindari optimasi prematur dan biaya overhead dalam pemrosesan paralel. Jawaban ini menjelaskan pilihan ideal struktur data untuk streaming paralel.
Sumber: Item # 48 Gunakan Perhatian Saat Membuat Streaming Paralel, Java 3e yang Efektif oleh Joshua Bloch
sumber
Jangan pernah mensejajarkan aliran tanpa batas dengan batas. Inilah yang terjadi:
Hasil
Sama jika Anda gunakan
.limit(...)
Penjelasan di sini: Java 8, menggunakan .parallel dalam aliran menyebabkan kesalahan OOM
Demikian pula, jangan gunakan paralel jika aliran diurutkan dan memiliki lebih banyak elemen daripada yang ingin Anda proses, misalnya
Ini mungkin berjalan lebih lama karena utas paralel dapat bekerja pada banyak rentang bilangan alih-alih yang penting 0-100, menyebabkan ini membutuhkan waktu yang sangat lama.
sumber