Saya telah memperhatikan bahwa beberapa aplikasi atau algoritma yang dibangun pada bahasa pemrograman, katakanlah C ++ / Rust berjalan lebih cepat atau lebih cepat daripada yang dibangun di atas, Java / Node.js, berjalan pada mesin yang sama. Saya punya beberapa pertanyaan tentang ini:
- Mengapa ini terjadi?
- Apa yang mengatur "kecepatan" bahasa pemrograman?
- Apakah ini ada hubungannya dengan manajemen memori?
Saya benar-benar akan menghargai jika seseorang memecahkan ini untuk saya.
programming-languages
compilers
evil_potato
sumber
sumber
Jawaban:
Dalam desain dan implementasi bahasa pemrograman, ada sejumlah besar pilihan yang dapat memengaruhi kinerja. Saya hanya akan menyebutkan beberapa.
Setiap bahasa pada akhirnya harus dijalankan dengan mengeksekusi kode mesin. Bahasa "dikompilasi" seperti C ++ diuraikan, didekodekan, dan diterjemahkan ke kode mesin hanya sekali, pada waktu kompilasi. Bahasa "ditafsirkan", jika diterapkan secara langsung, diterjemahkan pada saat runtime, pada setiap langkah, setiap waktu. Artinya, setiap kali kita menjalankan pernyataan, intepreter harus memeriksa apakah itu if-then-else, atau assignment, dll. Dan bertindak sesuai dengan itu. Ini berarti bahwa jika kita mengulang 100 kali, kita mendekode kode yang sama 100 kali, membuang-buang waktu. Untungnya, interpreter sering mengoptimalkan ini melalui misalnya sistem kompilasi just-in-time. (Lebih tepatnya, tidak ada yang namanya bahasa "dikompilasi" atau "ditafsirkan" - itu adalah properti dari implementasi, bukan bahasa. Namun,
Kompiler / juru bahasa yang berbeda melakukan optimasi yang berbeda pula.
Jika bahasa memiliki manajemen memori otomatis, implementasinya harus melakukan pengumpulan sampah. Ini memiliki biaya runtime, tetapi membebaskan programmer dari tugas yang rawan kesalahan.
Sebuah bahasa mungkin lebih dekat ke mesin, memungkinkan programmer ahli untuk mengoptimalkan semuanya secara mikro dan memeras lebih banyak kinerja dari CPU. Namun, dapat diperdebatkan apakah ini benar-benar bermanfaat dalam praktik, karena sebagian besar programmer tidak benar-benar mengoptimalkan mikro, dan seringkali bahasa tingkat yang lebih tinggi dapat dioptimalkan oleh kompiler lebih baik daripada apa yang akan dilakukan oleh programmer rata-rata. (Namun, kadang-kadang menjadi lebih jauh dari mesin mungkin memiliki manfaatnya juga! Misalnya, Haskell sangat tinggi, tetapi berkat pilihan desainnya, fitur benang hijau yang sangat ringan.)
Pengecekan tipe statis juga dapat membantu dalam optimasi. Dalam dinamis mengetik, bahasa ditafsirkan, setiap kali satu menghitung
x - y
, penafsir sering harus memeriksa apakah keduax,y
adalah nomor dan (misalnya) meningkatkan pengecualian sebaliknya. Pemeriksaan ini dapat dilewati jika jenis sudah diperiksa pada waktu kompilasi.Beberapa bahasa selalu melaporkan kesalahan runtime dengan cara yang waras. Jika Anda menulis
a[100]
di Java di manaa
hanya memiliki 20 elemen, Anda mendapatkan pengecualian runtime. Dalam C, itu akan menyebabkan perilaku yang tidak terdefinisi, yang berarti bahwa program mungkin macet, menimpa beberapa data acak dalam memori, atau bahkan benar - benar melakukan hal lain (standar ISO C tidak membatasi apa pun). Ini membutuhkan pemeriksaan runtime, tetapi memberikan semantik yang jauh lebih baik untuk programmer.Namun, perlu diingat bahwa, ketika mengevaluasi suatu bahasa, kinerja bukanlah segalanya. Jangan terobsesi dengan hal itu. Ini adalah perangkap umum untuk mencoba mengoptimalkan semuanya secara mikro, namun gagal menemukan bahwa algoritma / struktur data yang tidak efisien sedang digunakan. Knuth pernah berkata "optimasi prematur adalah akar dari semua kejahatan".
Jangan meremehkan betapa sulitnya menulis program dengan benar . Seringkali, bisa lebih baik untuk memilih bahasa "lebih lambat" yang memiliki semantik yang lebih ramah terhadap manusia. Lebih lanjut, jika ada beberapa bagian penting kinerja spesifik, mereka selalu dapat diimplementasikan dalam bahasa lain. Sama seperti referensi, dalam kontes pemrograman ICFP 2016 , ini adalah bahasa yang digunakan oleh pemenang:
Tak satu pun dari mereka menggunakan satu bahasa.
sumber
Tidak ada yang namanya "kecepatan" dari bahasa pemrograman. Hanya ada kecepatan program tertentu yang ditulis oleh progammer tertentu yang dieksekusi oleh versi tertentu dari implementasi tertentu dari mesin eksekusi tertentu yang berjalan dalam lingkungan tertentu.
Mungkin ada perbedaan kinerja yang sangat besar dalam menjalankan kode yang sama yang ditulis dalam bahasa yang sama pada mesin yang sama menggunakan implementasi yang berbeda. Atau bahkan menggunakan versi berbeda dari implementasi yang sama. Misalnya, menjalankan benchmark ECMAScript yang sama persis pada mesin yang sama persis menggunakan versi SpiderMonkey dari 10 tahun yang lalu vs versi dari tahun ini mungkin akan menghasilkan peningkatan kinerja di mana saja antara 2 × –5 ×, bahkan mungkin 10 ×. Apakah itu berarti ECMAScript 2x lebih cepat dari ECMAScript, karena menjalankan program yang sama pada mesin yang sama 2x lebih cepat dengan implementasi yang lebih baru? Itu tidak masuk akal.
Tidak juga.
Sumber daya. Uang. Microsoft mungkin mempekerjakan lebih banyak orang membuat kopi untuk programmer kompiler mereka daripada seluruh komunitas PHP, Ruby, dan Python digabungkan memiliki orang yang bekerja pada VM mereka.
Untuk lebih atau kurang fitur apa saja dari bahasa pemrograman yang memengaruhi kinerja dalam beberapa cara, ada juga solusinya. Misalnya, C (saya menggunakan C di sini sebagai pengganti untuk kelas bahasa yang serupa, beberapa di antaranya bahkan ada sebelum C) tidak aman untuk memori, sehingga beberapa program C yang berjalan pada saat yang sama dapat menginjak-injak memori masing-masing. Jadi, kami menciptakan memori virtual, dan membuat semua program C melewati lapisan tipuan sehingga mereka dapat berpura-pura mereka adalah satu-satunya yang berjalan pada mesin. Namun, itu lambat, dan karenanya, kami menciptakan MMU, dan mengimplementasikan memori virtual dalam perangkat keras untuk mempercepatnya.
Tapi! Bahasa memori-aman tidak membutuhkan semua itu! Memiliki memori virtual tidak membantu mereka sedikit pun. Sebenarnya, ini lebih buruk: tidak hanya memori virtual tidak membantu bahasa yang aman-memori, memori virtual, bahkan ketika diimplementasikan dalam perangkat keras, masih berdampak pada kinerja. Hal ini dapat sangat merusak kinerja pengumpul sampah (yang merupakan jumlah signifikan dari implementasi bahasa yang menggunakan memori aman).
Contoh lain: CPU modern mainstream umum menggunakan trik canggih untuk mengurangi frekuensi cache yang hilang. Banyak dari trik-trik itu sama dengan mencoba memprediksi kode apa yang akan dieksekusi dan memori apa yang akan dibutuhkan di masa depan. Namun, untuk bahasa dengan tingkat polimorfisme runtime yang tinggi (misalnya bahasa OO), sangat sulit untuk memprediksi pola akses tersebut.
Tapi, ada cara lain: total biaya kesalahan cache adalah jumlah kesalahan cache dikalikan dengan biaya miss cache individu. CPU arus utama mencoba untuk mengurangi jumlah kesalahan, tetapi bagaimana jika Anda dapat mengurangi biaya kehilangan individu?
CPU Azul Vega-3 dirancang khusus untuk menjalankan JVM tervirtualisasi, dan memiliki MMU yang sangat kuat dengan beberapa instruksi khusus untuk membantu pengumpulan sampah dan lolos dari deteksi (ekuivalen dinamis dengan analisis pelarian statis) dan pengontrol memori yang kuat, dan seluruh sistem masih bisa membuat kemajuan dengan lebih dari 20000 cache cache yang beredar dalam penerbangan. Sayangnya, seperti kebanyakan CPU khusus bahasa, desainnya hanya menghabiskan dan memaksa oleh "raksasa" Intel, AMD, IBM, dan sejenisnya.
Arsitektur CPU hanyalah salah satu contoh yang berdampak pada seberapa mudah atau sulitnya untuk memiliki implementasi bahasa yang berkinerja tinggi. Bahasa seperti C, C ++, D, Rust yang cocok untuk model pemrograman CPU arus utama modern akan lebih mudah dibuat lebih cepat daripada bahasa yang harus "berkelahi" dan mengelak dari CPU, seperti Java, ECMAScript, Python, Ruby , PHP.
Sungguh, itu semua masalah uang. Jika Anda menghabiskan jumlah uang yang sama untuk mengembangkan algoritme kinerja tinggi dalam ECMAScript, implementasi ECMAScript kinerja tinggi, sistem operasi berkinerja tinggi yang dirancang untuk ECMAScript, CPU berkinerja tinggi yang dirancang untuk ECMAScript sebagaimana telah dihabiskan selama yang terakhir beberapa dekade untuk membuat bahasa mirip-C berjalan cepat, maka Anda mungkin akan melihat kinerja yang sama. Hanya saja, pada saat ini, lebih banyak uang telah dihabiskan untuk membuat bahasa seperti C lebih cepat daripada membuat bahasa seperti ECMAScript, dan asumsi bahasa seperti C dimasukkan ke dalam seluruh tumpukan mulai dari MMU dan CPU hingga sistem operasi dan sistem memori virtual hingga pustaka dan kerangka kerja.
Secara pribadi, saya paling akrab dengan Ruby (yang umumnya dianggap sebagai "bahasa lambat"), jadi saya akan memberikan dua contoh:
Hash
kelas (salah satu struktur data pusat di Ruby, kamus kunci-nilai) di Rubinius Implementasi Ruby ditulis dalam 100% Ruby murni, dan memiliki kinerja yang hampir sama denganHash
kelas di YARV (implementasi yang paling banyak digunakan), yang ditulis dalam C. Dan ada perpustakaan manipulasi gambar yang ditulis sebagai ekstensi C untuk YARV, yang juga memiliki Ruby (versi fallback) "lambat" murni untuk implementasi yang tidak dapat mendukung C yang menggunakan banyak trik Ruby yang sangat dinamis dan reflektif; cabang eksperimental JRuby, memanfaatkan kerangka kerja juru bahasa Truffle AST dan kerangka kerja kompilasi Graal JIT oleh Oracle Labs, dapat mengeksekusi Ruby murni "versi mundur" secepat YARV dapat menjalankan versi C yang dioptimalkan dengan sangat tinggi. Ini hanya (well, apapun kecuali) dicapai oleh beberapa orang yang sangat pintar melakukan hal-hal yang sangat pintar dengan optimasi runtime dinamis, kompilasi JIT, dan evaluasi parsial.sumber
int
untuk alasan kinerja, terlepas dari kenyataan bahwa bilangan bulat tak terikat seperti yang digunakan oleh Python jauh lebih alami secara matematis. Menerapkan bilangan bulat tanpa batas dalam perangkat keras tidak akan secepat bilangan bulat ukuran tetap. Bahasa yang mencoba untuk menyembunyikan detail implementasi membutuhkan optimisasi yang kompleks untuk mendekati implementasi C naif.Secara teoritis, jika Anda menulis kode yang melakukan hal yang persis sama dalam dua bahasa dan mengkompilasi keduanya menggunakan kompiler "sempurna", kinerja keduanya harus sama.
Dalam praktiknya, ada beberapa alasan mengapa kinerja akan berbeda:
Beberapa bahasa lebih sulit untuk dioptimalkan.
Ini termasuk terutama fitur yang membuat kode lebih dinamis (pengetikan dinamis, metode virtual, fungsi pointer), tetapi juga untuk pengumpulan sampah misalnya.
Ada berbagai cara untuk membuat kode menggunakan fitur-fitur tersebut dengan cepat, tetapi biasanya masih berakhir setidaknya agak lebih lambat daripada tanpa menggunakannya.
Beberapa implementasi bahasa harus melakukan kompilasi saat runtime.
Ini berlaku terutama untuk bahasa dengan mesin virtual (seperti Java) dan bahasa yang mengeksekusi kode sumber, tanpa langkah menengah untuk biner (seperti JavaScript).
Implementasi bahasa seperti itu harus melakukan lebih banyak pekerjaan pada saat runtime, yang mempengaruhi kinerja, terutama waktu startup / kinerja segera setelah startup.
Implementasi bahasa sengaja menghabiskan lebih sedikit waktu untuk optimasi daripada yang mereka bisa.
Semua kompiler peduli tentang kinerja kompiler itu sendiri, bukan hanya dari kode yang dihasilkan. Ini terutama penting untuk kompiler runtime (kompiler JIT), di mana waktu yang terlalu lama untuk dikompilasi memperlambat eksekusi aplikasi. Tetapi ini berlaku untuk kompiler yang lebih dulu, seperti yang untuk C ++ juga. Misalnya alokasi register adalah masalah NP-complete, jadi tidak realistis untuk menyelesaikannya dengan sempurna dan sebaliknya heuristik yang mengeksekusi dalam waktu yang wajar digunakan.
Perbedaan idiom dalam berbagai bahasa.
Kode yang ditulis dengan gaya umum untuk bahasa tertentu (kode idiomatik) menggunakan perpustakaan umum dapat menghasilkan perbedaan dalam kinerja, karena kode idiomatik tersebut berperilaku berbeda secara halus dalam setiap bahasa.
Sebagai contoh, perhatikan
vector[i]
di C ++,list[i]
di C # danlist.get(i)
di Jawa. Kode C ++ kemungkinan tidak melakukan pengecekan jangkauan dan tidak melakukan panggilan virtual, kode C # melakukan pengecekan jangkauan, tetapi tidak ada panggilan virtual dan kode Java melakukan pengecekan jangkauan dan ini adalah panggilan virtual. Ketiga bahasa ini mendukung metode virtual dan non-virtual dan baik C ++ maupun C # dapat menyertakan pengecekan rentang atau menghindarinya saat mengakses array yang mendasarinya. Tetapi pustaka standar dari bahasa-bahasa ini memutuskan untuk menulis fungsi-fungsi yang setara ini secara berbeda, dan, sebagai konsekuensinya, kinerjanya akan berbeda.Beberapa kompiler mungkin kehilangan beberapa optimasi.
Penulis kompiler memiliki sumber daya yang terbatas, sehingga mereka tidak dapat menerapkan setiap optimasi yang mungkin, bahkan mengabaikan masalah lainnya. Dan sumber daya yang mereka miliki mungkin terfokus pada satu bidang optimasi lebih dari yang lain. Sebagai akibatnya, kode yang ditulis dalam bahasa yang berbeda dapat memiliki kinerja yang berbeda karena perbedaan dalam kompiler mereka, bahkan jika tidak ada alasan mendasar mengapa satu bahasa harus lebih cepat atau bahkan lebih mudah dioptimalkan daripada yang lain.
sumber
Ini adalah pertanyaan yang sangat umum, tetapi dalam kasus Anda jawabannya bisa sederhana. C ++ mengkompilasi ke kode mesin, di mana Java mengkompilasi ke kode byte Java, yang kemudian dijalankan dari mesin virtual Java (meskipun ada juga kompilasi just-in-time, yang selanjutnya mengkompilasi kode byte Java ke kode mesin asli). Perbedaan lainnya dapat berupa pengumpulan sampah, yang merupakan layanan yang hanya disediakan oleh Java.
sumber
Pertanyaan Anda terlalu umum, jadi saya khawatir saya tidak bisa memberikan jawaban yang tepat yang Anda butuhkan.
Untuk penjelasan terbaik saya, mari kita lihat platform C ++ dan .Net.
C + +, sangat dekat dengan kode mesin dan salah satu pemrograman yang disukai dalam waktu yang lebih lama (seperti lebih dari 10 tahun yang lalu?) Karena kinerja. Tidak banyak sumber daya yang dibutuhkan untuk mengembangkan dan menjalankan program C ++ bahkan dengan IDE, mereka dianggap sangat ringan dan sangat cepat. Anda juga dapat menulis kode C ++ di konsol dan mengembangkan game dari sana. Dalam hal memori dan sumber daya, saya lupa kira-kira berapa banyak kapasitas yang dibutuhkan dalam komputer tetapi kapasitasnya adalah sesuatu yang tidak dapat Anda bandingkan dengan generasi saat ini dalam bahasa pemrograman.
Sekarang mari kita lihat. Net. Prasyarat untuk melakukan pengembangan. Net adalah salah satu IDE raksasa yang terdiri dari tidak hanya satu jenis bahasa pemrograman. Bahkan jika Anda hanya ingin pengembang dalam katakanlah C #, IDE itu sendiri akan mencakup banyak platform pemrograman secara default seperti J #, VB, ponsel dan lain-lain secara default. Kecuali Anda menginstal kustom dan hanya menginstal persis apa yang Anda inginkan, asalkan Anda cukup berpengalaman untuk bermain dengan instalasi IDE.
Selain menginstal perangkat lunak IDE itu sendiri. Net juga dilengkapi dengan perpustakaan dan kerangka kerja berkapasitas besar untuk tujuan kemudahan akses ke segala jenis platform yang dibutuhkan pengembang DAN tidak perlu.
Berkembang di .Net bisa menjadi pengalaman yang menyenangkan karena banyak fungsi dan komponen umum tersedia secara default. Anda dapat menyeret-dan-jatuhkan dan menggunakan banyak metode validasi, membaca file, akses database, dan banyak lagi di IDE.
Akibatnya, ini merupakan pertukaran antara sumber daya komputer dan kecepatan pengembangan. Perpustakaan dan kerangka kerja tersebut membutuhkan memori dan sumber daya. Saat Anda menjalankan program dalam .Net IDE, mungkin perlu banyak waktu untuk mencoba mengkompilasi pustaka, komponen, dan semua file Anda. Dan ketika Anda melakukan debugging, komputer Anda membutuhkan banyak sumber daya untuk mengelola proses debugging di IDE Anda.
Biasanya, untuk melakukan pengembangan. Net, Anda memerlukan komputer yang bagus dengan beberapa Ram dan prosesor. Jika tidak, Anda mungkin tidak memprogram sama sekali. Dalam aspek ini, platform C ++ jauh lebih baik daripada .Net. Meskipun Anda masih membutuhkan komputer yang bagus, tetapi kapasitas tidak akan terlalu menjadi masalah dibandingkan dengan .Net.
Semoga jawaban saya dapat membantu dengan pertanyaan Anda. Beri tahu saya jika Anda ingin tahu lebih banyak.
SUNTING:
Hanya klarifikasi ke poin utama saya, saya terutama menjawab pertanyaan "Apa yang mengatur kecepatan pemrograman".
Dalam sudut pandang IDE, menggunakan bahasa C ++ atau .Net di IDE relatif tidak mempengaruhi kecepatan penulisan kode, tetapi akan mempengaruhi kecepatan pengembangan karena kompiler Visual Studio membutuhkan waktu lebih lama untuk menjalankan program, tetapi C ++ IDE jauh lebih ringan dan mengkonsumsi lebih sedikit sumber daya komputer. Jadi dalam jangka panjang, Anda dapat melakukan pemrograman lebih cepat dengan tipe C ++ IDE dibandingkan dengan .Net IDE yang sangat bergantung pada pustaka dan framework. Jika Anda mengambil dalam jumlah waktu menunggu IDE untuk memulai, mengkompilasi, menjalankan program dan lain-lain, itu akan mempengaruhi kecepatan pemrograman. Kecuali "kecepatan pemrograman" sebenarnya hanya fokus pada "kecepatan menulis kode".
Jumlah perpustakaan dan kerangka kerja di Visual Studio juga mengkonsumsi kapasitas komputer. Saya tidak yakin apakah ini menjawab pertanyaan "manajemen memori", tapi saya hanya ingin menunjukkan bahwa Visual Studio IDE dapat mengambil banyak sumber daya saat menjalankannya, dan dengan demikian memperlambat keseluruhan "kecepatan pemrograman". Tentu saja, ini tidak ada hubungannya dengan "kecepatan penulisan kode".
Seperti yang mungkin sudah Anda duga, saya tidak tahu terlalu banyak tentang C ++ karena saya hanya menggunakannya sebagai contoh, poin utama saya adalah tentang tipe Visual Studio dari IDE berat yang menggunakan sumber daya komputer.
Jika saya mendapat ide dan sama sekali tidak menjawab pertanyaan pembuka utas, mohon maaf untuk posting lama. Tapi saya akan menyarankan pemula thread untuk membuat pertanyaan yang jelas dan bertanya apa yang dia perlu tahu tentang "lebih cepat" dan "lebih lambat"
sumber