Terkadang Java mengungguli C ++ dalam tolok ukur. Tentu saja, kadang-kadang C ++ mengungguli.
Lihat tautan berikut:
- http://keithlea.com/javabench/
- http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy/
- http://blog.cfelde.com/2010/06/c-vs-java-performance/
Tetapi bagaimana ini mungkin? Ini mengejutkan saya bahwa interpretasi bytecode bisa lebih cepat daripada bahasa yang dikompilasi.
Bisakah seseorang tolong jelaskan? Terima kasih!
java
c++
performance
Deets McGeets
sumber
sumber
Jawaban:
Pertama, sebagian besar JVM termasuk kompiler, jadi "interpretasi bytecode" sebenarnya cukup langka (setidaknya dalam kode benchmark - itu tidak cukup langka dalam kehidupan nyata, di mana kode Anda biasanya lebih dari beberapa loop sepele yang diulang sangat sering ).
Kedua, cukup banyak tolok ukur yang terlibat tampaknya cukup bias (apakah dengan niat atau tidak kompeten, saya tidak bisa mengatakannya). Sebagai contoh, bertahun-tahun yang lalu saya melihat beberapa kode sumber yang ditautkan dari salah satu tautan yang Anda posting. Itu kode seperti ini:
Karena
calloc
menyediakan memori yang sudah memusatkan perhatian, menggunakanfor
loop ke nol lagi jelas tidak berguna. Ini diikuti (jika memori berfungsi) dengan mengisi memori dengan data lain (dan tidak ada ketergantungan pada itu yang memusatkan perhatian), jadi semua penekanan itu sama sekali tidak perlu. Mengganti kode di atas dengan yang sederhanamalloc
(seperti orang waras yang akan digunakan untuk memulainya) meningkatkan kecepatan versi C ++ cukup untuk mengalahkan versi Java (dengan selisih yang cukup lebar, jika memori berfungsi).Pertimbangkan (untuk contoh lain)
methcall
patokan yang digunakan dalam entri blog di tautan terakhir Anda. Terlepas dari namanya (dan bagaimana hal-hal bahkan terlihat), versi C ++ ini tidak benar - benar mengukur banyak tentang overhead panggilan metode sama sekali. Bagian dari kode yang ternyata kritis adalah di kelas Toggle:Bagian penting ternyata adalah
state = !state;
. Pertimbangkan apa yang terjadi ketika kami mengubah kode untuk menyandikan status sebagaiint
alih - alihbool
:Perubahan kecil ini meningkatkan kecepatan keseluruhan sekitar 5: 1 margin . Meskipun tolok ukur dimaksudkan untuk mengukur waktu pemanggilan metode, pada kenyataannya sebagian besar yang diukur adalah waktu untuk mengkonversi antara
int
danbool
. Saya pasti setuju bahwa ketidakefisienan yang ditunjukkan oleh dokumen asli sangat disayangkan - tetapi mengingat betapa jarang hal itu muncul dalam kode nyata, dan kemudahan untuk memperbaikinya ketika / jika muncul, saya mengalami kesulitan untuk berpikir itu sangat berarti.Jika ada yang memutuskan untuk menjalankan kembali tolok ukur yang terlibat, saya juga harus menambahkan bahwa ada modifikasi yang hampir sama sepele untuk versi Java yang menghasilkan (atau setidaknya pada satu waktu diproduksi - saya belum menjalankan kembali tes dengan JVM baru-baru ini untuk mengkonfirmasi mereka masih melakukan) peningkatan yang cukup besar dalam versi Java juga. Versi Java memiliki NthToggle :: activate () yang terlihat seperti ini:
Mengubah ini untuk memanggil fungsi dasar alih-alih memanipulasi
this.state
secara langsung memberikan peningkatan kecepatan yang cukup besar (meskipun tidak cukup untuk mengikuti versi C ++ yang dimodifikasi).Jadi, yang akhirnya kita dapatkan adalah asumsi yang salah tentang kode byte yang ditafsirkan vs beberapa tolok ukur terburuk (yang pernah saya lihat). Tidak ada yang memberikan hasil yang berarti.
Pengalaman saya sendiri adalah bahwa dengan programmer yang sama-sama berpengalaman memberikan perhatian yang sama untuk mengoptimalkan, C ++ akan mengalahkan Java lebih sering daripada tidak - tetapi (setidaknya di antara keduanya), bahasa jarang akan membuat perbedaan sebanyak programmer dan desain. Tolok ukur yang dikutip memberi tahu kami lebih banyak tentang kompetensi (dalam) / kejujuran penulis mereka daripada yang mereka lakukan tentang bahasa yang mereka maksud untuk dijadikan patokan.
[Sunting: Seperti yang tersirat di satu tempat di atas tetapi tidak pernah dinyatakan secara langsung seperti yang seharusnya saya miliki, hasil yang saya kutip adalah yang saya dapatkan ketika saya menguji ini ~ 5 tahun yang lalu, menggunakan implementasi C ++ dan Java yang saat ini ada pada saat itu . Saya belum menjalankan kembali tes dengan implementasi saat ini. Pandangan sekilas, menunjukkan bahwa kode belum diperbaiki, jadi semua yang akan berubah adalah kemampuan kompiler untuk menutupi masalah dalam kode.]
Jika kita mengabaikan contoh Java, bagaimanapun, adalah sebenarnya mungkin untuk kode ditafsirkan untuk berjalan lebih cepat daripada kode dikompilasi (meskipun sulit dan agak tidak biasa).
Cara biasa ini terjadi adalah bahwa kode yang ditafsirkan jauh lebih kompak daripada kode mesin, atau itu berjalan pada CPU yang memiliki cache data yang lebih besar daripada kode cache.
Dalam kasus seperti itu, juru bahasa kecil (misalnya, juru bahasa dalam implementasi Keempat) mungkin dapat masuk sepenuhnya dalam cache kode, dan program yang ditafsirkan sepenuhnya cocok dalam cache data. Cache biasanya lebih cepat dari memori utama dengan faktor setidaknya 10, dan seringkali jauh lebih (faktor 100 tidak terlalu jarang lagi).
Jadi, jika cache lebih cepat dari memori utama dengan faktor N, dan dibutuhkan lebih sedikit dari instruksi kode mesin N untuk mengimplementasikan setiap kode byte, kode byte harus menang (saya menyederhanakan, tapi saya pikir ide umum masih harus menjadi jelas).
sumber
Hand rolled C / C ++ yang dilakukan oleh seorang ahli dengan waktu tidak terbatas akan setidaknya secepat atau lebih cepat dari Java. Pada akhirnya, Java itu sendiri ditulis dalam C / C ++ sehingga Anda tentu saja dapat melakukan semua yang dilakukan Java jika Anda bersedia melakukan upaya rekayasa yang cukup.
Namun dalam praktiknya, Java sering dieksekusi sangat cepat karena alasan berikut:
Pada saat yang sama C / C ++ juga memiliki beberapa keunggulan:
Secara keseluruhan:
sumber
Java runtime tidak menafsirkan bytecode. Sebaliknya, ia menggunakan whats yang disebut Just In Time Compilation . Pada dasarnya, ketika program dijalankan, ia mengambil bytecode dan mengubahnya menjadi kode asli yang dioptimalkan untuk CPU tertentu.
sumber
Semua hal dianggap sama, Anda dapat mengatakan: tidak, Java seharusnya tidak pernah lebih cepat . Anda selalu dapat mengimplementasikan Java dalam C ++ dari awal dan karenanya mendapatkan kinerja yang setidaknya sama baiknya. Namun dalam praktiknya:
Sebagai tambahan, ini mengingatkan saya pada perdebatan tentang C di tahun 80-an / 90-an. Semua orang bertanya-tanya, "bisakah C secepat perakitan?" Pada dasarnya, jawabannya adalah: tidak di atas kertas, tetapi pada kenyataannya kompiler C menciptakan kode yang lebih efisien daripada 90% dari programer perakitan (baik, setelah sedikit matang).
sumber
http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html
sumber
Sementara program Java yang sepenuhnya dioptimalkan jarang akan mengalahkan program C ++ yang sepenuhnya dioptimalkan, perbedaan dalam hal-hal seperti manajemen memori dapat membuat banyak algoritma diimplementasikan secara idiomatis di Jawa lebih cepat daripada algoritma yang sama yang diimplementasikan secara idiomatis di C ++.
Seperti yang ditunjukkan oleh @Jerry Coffin, ada banyak kasus di mana perubahan sederhana dapat membuat kode lebih cepat - tetapi seringkali terlalu banyak perubahan yang tidak jelas dalam satu bahasa atau yang lain untuk peningkatan kinerja menjadi berharga. Itu mungkin yang akan Anda lihat dalam tolok ukur yang baik yang menunjukkan Java melakukan lebih baik daripada C ++.
Juga, meskipun biasanya tidak terlalu signifikan, ada beberapa optimasi kinerja yang bisa dilakukan oleh bahasa JIT seperti Java yang tidak dapat dilakukan C ++. Java runtime dapat menyertakan peningkatan setelah kode dikompilasi, yang berarti bahwa JIT berpotensi menghasilkan kode yang dioptimalkan untuk memanfaatkan fitur CPU yang baru (atau setidaknya berbeda). Untuk alasan ini, biner Java 10 tahun yang berpotensi mengungguli biner C ++ 10 tahun.
Terakhir, keamanan tipe lengkap dalam gambar yang lebih besar dapat, dalam kasus yang sangat jarang, menawarkan peningkatan kinerja yang ekstrem. Singularity , sebuah OS eksperimental yang ditulis hampir seluruhnya dalam bahasa berbasis C #, memiliki komunikasi antar proses yang jauh lebih cepat dan multitasking karena kenyataan bahwa tidak perlu untuk batasan proses perangkat keras atau switch konteks yang mahal.
sumber
Diposting oleh Tim Holloway di JavaRanch:
Sumber: http://www.coderanch.com/t/547458/Performance/java/Ahead-Time-vs-Just-time
sumber
Itu karena langkah terakhir menghasilkan kode mesin terjadi secara transparan di dalam JVM saat menjalankan program Java Anda, alih-alih secara eksplisit saat membuat proram C ++ Anda.
Anda harus mempertimbangkan fakta bahwa JVM modern menghabiskan cukup banyak waktu mengkompilasi kode byte dengan cepat ke kode mesin asli untuk membuatnya secepat mungkin. Ini memungkinkan JVM untuk melakukan semua jenis trik kompiler yang bisa lebih baik dengan mengetahui data profil dari program yang sedang dijalankan.
Hanya hal seperti secara otomatis inter pengambil, sehingga JUMP-RETURN tidak diperlukan untuk hanya mendapatkan nilai, mempercepat sesuatu.
Namun, hal yang benar-benar memungkinkan program cepat adalah pembersihan yang lebih baik setelahnya. Mekanisme pengumpulan sampah di Jawa lebih cepat daripada manual bebas malloc di C. Banyak implementasi bebas malloc modern menggunakan pemulung di bawahnya.
sumber
Jawaban singkat - tidak. Lupakan saja, topiknya setua api atau roda. Java atau .NET tidak dan tidak akan lebih cepat dari C / C ++. Cukup cepat untuk sebagian besar tugas di mana Anda tidak perlu memikirkan pengoptimalan sama sekali. Seperti formulir dan pemrosesan SQL, tapi di situlah akhirnya.
Untuk tolok ukur, atau aplikasi kecil yang ditulis oleh pengembang yang tidak kompeten ya, hasil akhirnya adalah bahwa Java / .NET mungkin akan menjadi dekat dan mungkin bahkan lebih cepat.
Pada kenyataannya, hal-hal sederhana seperti mengalokasikan memori pada stack, atau hanya menggunakan memzones hanya akan mematikan Java / .NET di tempat.
Dunia pengumpulan sampah menggunakan semacam memzone dengan segala akuntingnya. Tambahkan memzone ke C dan C akan lebih cepat di sana di tempat. Khusus untuk tolok ukur "vs. kode kinerja" Java vs. C, yang berlaku seperti ini:
Cobalah untuk menggunakan variabel berbasis stack dalam C / C ++ (atau penempatan baru), mereka menerjemahkannya ke dalam
sub esp, 0xff
, itu adalah instruksi x86 tunggal, kalahkan dengan Java - Anda tidak dapat ...Sebagian besar waktu saya melihat bangku-bangku di mana Java terhadap C ++ dibandingkan menyebabkan saya pergi seperti, wth? Strategi alokasi memori yang salah, wadah yang tumbuh sendiri tanpa cadangan, banyak yang baru. Ini bahkan tidak dekat dengan kode C / C ++ yang berorientasi pada kinerja.
Juga bacaan yang bagus: https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf
sumber
Kenyataannya adalah mereka berdua hanya perakit tingkat tinggi yang melakukan persis apa yang disuruh programmer kepada mereka, tepatnya bagaimana programmer memberi tahu mereka dalam urutan yang tepat yang dikatakan oleh programmer. Perbedaan kinerja sangat kecil sehingga tidak penting untuk semua tujuan praktis.
Bahasa tidak "lambat", programmer menulis program lambat. Jarang sekali sebuah program menulis cara terbaik dalam satu bahasa lebih baik daripada (untuk tujuan praktis apa pun) program melakukan hal yang sama dengan menggunakan cara terbaik dari bahasa alternatif, kecuali jika penulis studi keluar untuk menggiling kapak khususnya.
Jelas jika Anda akan menggunakan case tepi yang langka seperti sistem embedded realtime yang sulit, pilihan bahasa dapat membuat perbedaan, tetapi seberapa sering hal ini terjadi? dan dari kasus-kasus itu, seberapa sering pilihan yang tepat tidak begitu jelas.
sumber
Keith Lea memberi tahu Anda ada "kekurangan yang jelas" tetapi tidak melakukan apa pun tentang "kekurangan yang jelas" itu. Kembali pada tahun 2005 tugas-tugas lama itu dibuang dan diganti dengan tugas-tugas yang sekarang ditampilkan dalam permainan tolok ukur .
Keith Lea memberi tahu Anda bahwa ia "mengambil kode tolok ukur untuk C ++ dan Java dari Great Computer Language Shootout yang sudah usang dan menjalankan tes" tetapi sebenarnya ia hanya menunjukkan pengukuran untuk 14 dari 25 tes yang sudah ketinggalan zaman .
Keith Lea sekarang memberitahu Anda bahwa dia tidak berusaha membuktikan apa pun dengan posting blog tujuh tahun sebelumnya, tetapi saat itu dia berkata, "Saya muak mendengar orang mengatakan Jawa lambat, ketika saya tahu itu cukup cepat ..." yang menunjukkan saat itu ada sesuatu yang dia coba buktikan.
Christian Felde memberi tahu Anda, "Saya tidak membuat kode, hanya menjalankan ulang tes." seolah-olah itu membebaskannya dari tanggung jawab atas keputusannya untuk mempublikasikan pengukuran tugas dan program yang dipilih Keith Lea.
Apakah pengukuran bahkan 25 program kecil mungil memberikan bukti pasti?
Pengukuran tersebut untuk program yang dijalankan sebagai "mode campuran" Java tidak menafsirkan Java - "Ingat cara kerja HotSpot." Anda dapat dengan mudah mengetahui seberapa baik Java menjalankan "interpreted bytecode", karena Anda dapat memaksa Java untuk hanya menafsirkan bytecode - cukup gunakan waktu beberapa program Java dengan dan tanpa opsi -Xint.
sumber
Ini menghibur saya betapa meresap gagasan aneh "ditafsirkan bytecode" ini. Pernahkah Anda mendengar tentang kompilasi JIT? Argumen Anda tidak dapat diterapkan ke Java.
Tetapi, mengesampingkan JVM, ada kasus ketika kode berulir langsung atau bahkan interpretasi bytecode sepele dapat dengan mudah mengungguli kode asli yang sangat dioptimalkan. Penjelasannya cukup sederhana: bytecode bisa sangat ringkas dan akan cocok dengan cache kecil Anda ketika versi kode asli dari algoritma yang sama akan berakhir memiliki beberapa kesalahan cache untuk satu iterasi tunggal.
sumber
JIT, GC dan sebagainya, C ++ bisa sangat, sangat mudah dibuat lebih lambat dari Jawa. Ini tidak akan muncul di tolok ukur, tetapi aplikasi yang sama yang ditulis oleh pengembang Java dan pengembang C ++ mungkin jauh lebih cepat di Jawa.
Adapun pola pewarisan lanjutan, ini hampir mirip - C + + memiliki beberapa yang tidak Java dan sebaliknya, tetapi semuanya memperkenalkan overhead yang signifikan juga. Jadi tidak ada keunggulan khusus C ++ dalam pemrograman objek-berat.
Satu lagi peringatan: GC bisa lebih cepat atau lebih lambat daripada mengelola alokasi secara manual. Jika Anda mengalokasikan banyak objek kecil, dalam lingkungan GC biasanya sepotong memori dialokasikan dan potongan-potongan itu dikirim sesuai kebutuhan untuk objek baru. Dalam dikelola - setiap objek = alokasi terpisah membutuhkan waktu yang signifikan. OTOH, jika Anda malloc () banyak memori sekaligus dan kemudian hanya memberikan potongan-potongan itu ke objek Anda secara manual, atau menggunakan beberapa contoh objek yang lebih besar, Anda mungkin muncul lebih cepat.
sumber
obj.fetchFromDatabase("key")
tiga kali dalam lima baris kode untuk kunci yang sama, Anda akan berpikir dua kali apakah akan mengambil nilai itu sekali dan menyimpannya dalam variabel lokal. Jika Anda menulisobj->"key"
dengan->
kelebihan beban untuk bertindak sebagai pengambilan basis data, Anda jauh lebih rentan untuk membiarkannya berlalu karena biaya operasi tidak jelas.Entah bagaimana Stack Exchange tidak mengambil stackpoint saya yang lain jadi ... sayangnya tidak ada balasan ...
Namun jawaban terbanyak kedua di sini penuh dengan informasi yang salah dalam pendapat saya yang sederhana.
Aplikasi linting tangan oleh pakar C / C ++ SELALU akan jauh lebih cepat daripada aplikasi Java, titik. Tidak ada 'secepat Java atau Lebih Cepat'. hanya saja lebih cepat, justru karena item yang Anda kutip di bawah ini:
Kompilasi JIT : Apakah Anda benar-benar mengharapkan pengoptimal otomatis memiliki kecerdasan programmer ahli dan melihat tautan antara maksud dan kode yang benar-benar dijalankan CPU ??? Selain itu, semua JIT yang Anda lakukan adalah waktu yang hilang dibandingkan dengan program yang sudah dikompilasi.
Garbage Collection adalah alat yang secara sederhana mengalokasikan sumber daya yang lupa dilupakan oleh pemrogram, dengan cara yang lebih atau kurang efisien.
Jelas ini hanya bisa lebih lambat dari apa yang dilakukan oleh seorang ahli (Anda memilih istilahnya) programmer C untuk menangani ingatannya (dan tidak ada kebocoran pada aplikasi yang ditulis dengan benar).
Aplikasi C yang dioptimalkan kinerja mengetahui bahwa CPU sedang berjalan, sudah dikompilasi, apakah itu berarti Anda tidak cukup mengambil semua langkah untuk kinerja, bukan?
Statistik Runtime Ini di luar pengetahuan saya, tetapi saya curiga bahwa seorang pakar di C memiliki lebih dari cukup pengetahuan prediksi cabang untuk mengakali lagi optimasi otomatis -
Perpustakaan yang sangat baik Ada banyak fungsi yang tidak dioptimalkan yang tersedia melalui perpustakaan di Jawa, dan hal yang sama berlaku dalam bahasa apa pun, namun perpustakaan yang paling optimal ditulis dalam C, terutama untuk perhitungan.
JVM adalah lapisan abstraksi, yang menyiratkan kedua hal baik yang banyak di atas, dan juga menyiratkan bahwa solusi keseluruhan lebih lambat oleh desain.
Secara keseluruhan:
Java tidak pernah dapat mencapai kecepatan C / C ++ karena cara kerjanya di JVM dengan banyak perlindungan, fitur dan alat.
C ++ memiliki keunggulan yang jelas dalam perangkat lunak yang dioptimalkan, baik itu untuk komputasi atau permainan, dan itu biasa untuk melihat implementasi C ++ memenangkan kontes pengkodean hingga titik bahwa implementasi Java terbaik hanya dapat dilihat di halaman kedua.
Dalam praktiknya C ++ bukan mainan dan tidak akan membiarkan Anda lolos dengan banyak kesalahan yang dapat ditangani oleh sebagian besar bahasa modern, namun dengan menjadi lebih sederhana dan kurang aman, itu pada dasarnya lebih cepat.
Dan sebagai kesimpulan, saya ingin mengatakan bahwa kebanyakan orang tidak memberikan dua sen tentang ini, bahwa pada akhirnya optimalisasi adalah olahraga yang hanya dimiliki oleh beberapa pengembang yang beruntung dan bahwa kecuali dalam kasus di mana kinerja benar-benar menjadi perhatian. (yaitu ketika mengalikan perangkat keras dengan 10 tidak akan membantu Anda - atau setidaknya mewakili jutaan), sebagian besar manajer akan lebih memilih aplikasi yang tidak dioptimalkan dan satu ton perangkat keras.
sumber
new
ataumalloc()
. Ini bisa menjadi jauh lebih cepat secara umum daripada manajemen memori manual - karena Anda tidak akan dapat memindahkan objek secara manual. Jadi, semua alasan Anda jelas salah dan bias. Pengetahuan Anda tentang algoritma GC dan metode optimisasi JIT terlalu terbatas.Saya telah melihat setidaknya dua mmo mengesankan dilakukan di Jawa, untuk mengatakan itu tidak cukup cepat untuk permainan adalah keliru. Hanya karena para perancang game lebih menyukai C ++ daripada bahasa lain mengatakan itu tidak hanya terkait dengan Java, itu hanya berarti bahwa programmer tidak pernah benar-benar mencoba-coba bahasa pemrograman / paradigma lain. Apa pun dalam bahasa apa pun semaju C / C ++ atau bahkan Java dapat menghasilkan kode yang secara teknis dapat memenuhi atau mengalahkan argumen kecepatan. Semua yang dikatakan dengan baik berasal dari apa yang diketahui pemrogram, tim apa yang paling cocok bekerja dan yang paling penting mengapa mereka menggunakan alat tersebut. Karena kita menangani aspek pengembangan game dari pemrograman, maka harus ada lebih banyak argumen. Sederhananya ' Semua tentang uang dan waktu untuk bisnis yang mati karena menggunakan alat yang memenuhi QA dan di dunia nyata tidak mempermasalahkan alasan xx untuk memilih C ++ di Jawa atau bahasa lainnya. Itu hanya keputusan produksi massal. Pada level paling dasar dari algoritma komputasi yang kita mainkan adalah satu dan nol, argumen kecepatan adalah salah satu argumen paling bodoh yang pernah diterapkan pada gaming. Jika Anda menginginkan peningkatan kecepatan yang buruk maka hilangkan bahasa pemrograman sepenuhnya dan bekerja dengan perakitan yang mungkin merupakan keuntungan terbaik sejauh ini.
sumber