Seorang kolega saya hari ini melakukan kelas yang disebut ThreadLocalFormat
, yang pada dasarnya memindahkan instance kelas Java Format ke thread lokal, karena mereka tidak aman untuk thread dan "relatif mahal" untuk dibuat. Saya menulis tes cepat dan menghitung bahwa saya dapat membuat 200.000 instance per detik, bertanya kepadanya apakah dia menciptakan banyak, yang dia jawab "tidak jauh dari banyak itu". Dia adalah programmer yang hebat dan semua orang di tim sangat terampil sehingga kami tidak memiliki masalah dalam memahami kode yang dihasilkan, tapi itu jelas merupakan kasus optimalisasi di mana tidak ada kebutuhan nyata. Dia mundur kode atas permintaan saya. Bagaimana menurut anda? Apakah ini kasus "optimisasi prematur" dan seberapa buruk itu sebenarnya?
sumber
Jawaban:
Penting untuk diingat kutipan lengkap:
Artinya, tanpa adanya masalah kinerja yang diukur, Anda tidak boleh mengoptimalkan karena Anda pikir Anda akan mendapatkan peningkatan kinerja. Ada optimasi yang jelas (seperti tidak melakukan rangkaian string di dalam loop ketat) tetapi apa pun yang bukan optimasi yang jelas sepele harus dihindari sampai dapat diukur.
Masalah terbesar dengan "optimisasi prematur" adalah ia dapat memperkenalkan bug yang tidak terduga dan bisa menjadi pemboros waktu yang sangat besar.
sumber
HashSet
bukanList
optimasi prematur. Kasus penggunaan yang dimaksud adalah koleksi yang diinisialisasi secara statis yang satu-satunya tujuan adalah untuk berfungsi sebagai tabel pencarian. Saya tidak berpikir saya salah mengatakan ada perbedaan dalam memilih alat yang tepat untuk pekerjaan versus pengoptimalan prematur. Saya pikir posting Anda mengonfirmasi filosofi ini:There are obvious optimizations...anything that isn't trivially clear optimization should be avoided until it can be measured.
Optimalisasi HashSet telah diukur dan didokumentasikan dengan seksama.Set
semantik lebih benar dan informatif daripadaList
, jadi ada lebih dari aspek optimasi untuk itu.Optimalisasi mikro prematur adalah akar dari semua kejahatan, karena optimisasi mikro mengabaikan konteks. Mereka hampir tidak pernah berperilaku seperti yang diharapkan.
Apa saja optimasi awal yang baik dalam urutan kepentingan:
Beberapa optimisasi siklus pertengahan pengembangan:
Beberapa optimisasi akhir siklus pengembangan
Tidak semua optimisasi awal adalah jahat, optimisasi mikro jahat jika dilakukan pada waktu yang salah dalam siklus hidup pengembangan , karena mereka dapat mempengaruhi arsitektur secara negatif, dapat secara negatif mempengaruhi produktivitas awal, dapat menjadi kinerja yang tidak relevan, bijaksana atau bahkan memiliki efek yang merugikan pada akhirnya. pembangunan karena kondisi lingkungan yang berbeda.
Jika kinerja menjadi perhatian (dan selalu harus) selalu berpikir besar . Kinerja adalah gambaran yang lebih besar dan bukan tentang hal-hal seperti: haruskah saya menggunakan int atau panjang ? Gunakan Top Down saat bekerja dengan kinerja alih-alih Bottom Up .
sumber
optimasi tanpa pengukuran pertama hampir selalu prematur.
Saya percaya itu benar dalam kasus ini, dan benar dalam kasus umum juga.
sumber
Optimalisasi adalah "jahat" jika menyebabkan:
Dalam kasus Anda, sepertinya sedikit waktu programmer sudah dihabiskan, kodenya tidak terlalu rumit (tebakan dari komentar Anda bahwa semua orang di tim akan dapat memahami), dan kodenya sedikit lebih banyak bukti masa depan (menjadi utas aman sekarang, jika saya mengerti uraian Anda). Kedengarannya hanya sedikit jahat. :)
sumber
Saya terkejut bahwa pertanyaan ini berumur 5 tahun, namun belum ada yang memposting lebih banyak dari apa yang Knuth katakan daripada beberapa kalimat. Beberapa paragraf yang mengelilingi kutipan terkenal menjelaskannya dengan cukup baik. Makalah yang dikutip disebut " Pemrograman Terstruktur dengan pergi ke Pernyataan ", dan sementara itu hampir 40 tahun, adalah tentang kontroversi dan gerakan perangkat lunak yang keduanya tidak ada lagi, dan memiliki contoh dalam bahasa pemrograman yang banyak orang tidak pernah mendengar, sejumlah besar mengejutkan dari apa yang dikatakannya masih berlaku.
Berikut ini kutipan yang lebih besar (dari halaman 8 dari pdf, halaman 268 dalam aslinya):
Bit bagus lain dari halaman sebelumnya:
sumber
Saya sering melihat kutipan ini digunakan untuk membenarkan kode yang jelas buruk atau kode yang, meskipun kinerjanya belum diukur, mungkin dapat dibuat lebih cepat dengan mudah, tanpa meningkatkan ukuran kode atau mengurangi keterbacaannya.
Secara umum, saya pikir optimasi mikro awal mungkin merupakan ide yang buruk. Namun, optimasi makro (hal-hal seperti memilih algoritma O (log N) daripada O (N ^ 2)) sering bermanfaat dan harus dilakukan lebih awal, karena mungkin boros untuk menulis algoritma O (N ^ 2) dan kemudian buang sepenuhnya demi pendekatan O (log N).
Perhatikan kata-kata mungkin : jika O (N ^ 2) algoritma sederhana dan mudah untuk menulis, Anda bisa membuangnya kemudian tanpa banyak rasa bersalah jika ternyata menjadi terlalu lambat. Tetapi jika kedua algoritma itu sama kompleksnya, atau jika beban kerja yang diharapkan begitu besar sehingga Anda sudah tahu Anda akan membutuhkan yang lebih cepat, maka mengoptimalkan lebih awal adalah keputusan rekayasa suara yang akan mengurangi total beban kerja Anda dalam jangka panjang.
Jadi, secara umum, saya pikir pendekatan yang tepat adalah untuk mengetahui apa pilihan Anda sebelum Anda mulai menulis kode, dan secara sadar memilih algoritma terbaik untuk situasi Anda. Yang paling penting, ungkapan "optimisasi prematur adalah akar dari semua kejahatan" bukanlah alasan untuk ketidaktahuan. Pengembang karir harus memiliki gagasan umum tentang berapa biaya operasi umum; mereka harus tahu, misalnya,
Dan pengembang harus terbiasa dengan kotak peralatan struktur data dan algoritma sehingga mereka dapat dengan mudah menggunakan alat yang tepat untuk pekerjaan itu.
Memiliki banyak pengetahuan dan kotak peralatan pribadi memungkinkan Anda untuk mengoptimalkan hampir dengan mudah. Menempatkan banyak upaya ke dalam optimasi yang mungkin tidak perlu adalah kejahatan (dan saya akui jatuh ke dalam perangkap itu lebih dari sekali). Tetapi ketika optimasi semudah memilih set / hashtable alih-alih array, atau menyimpan daftar angka dalam double [] bukannya string [], lalu mengapa tidak? Saya mungkin tidak setuju dengan Knuth di sini, saya tidak yakin, tapi saya pikir dia berbicara tentang optimasi tingkat rendah sedangkan saya berbicara tentang optimasi tingkat tinggi.
Ingat, kutipan itu awalnya dari 1974. Pada 1974 komputer lambat dan daya komputasi mahal, yang memberi beberapa pengembang kecenderungan untuk terlalu mengoptimalkan, baris demi baris. Saya pikir itulah yang mendorong Knuth. Dia tidak mengatakan "jangan khawatir tentang kinerja sama sekali", karena pada tahun 1974 itu hanya akan menjadi pembicaraan gila. Knuth menjelaskan cara mengoptimalkan; singkatnya, seseorang harus fokus hanya pada kemacetan, dan sebelum Anda melakukannya, Anda harus melakukan pengukuran untuk menemukan kemacetan.
Perhatikan bahwa Anda tidak dapat menemukan hambatan sampai Anda menulis program untuk diukur, yang berarti bahwa beberapa keputusan kinerja harus dibuat sebelum segala sesuatu ada untuk diukur. Terkadang keputusan ini sulit diubah jika Anda salah. Untuk alasan ini, ada baiknya memiliki gagasan umum tentang biaya apa saja sehingga Anda dapat membuat keputusan yang masuk akal ketika tidak ada data keras yang tersedia.
Seberapa dini untuk mengoptimalkan, dan seberapa besar kekhawatiran tentang kinerja tergantung pada pekerjaan. Saat menulis skrip yang hanya akan Anda jalankan beberapa kali, mengkhawatirkan kinerja sama sekali biasanya hanya membuang waktu. Tetapi jika Anda bekerja untuk Microsoft atau Oracle dan Anda sedang bekerja di perpustakaan yang akan digunakan oleh ribuan pengembang lain dalam ribuan cara yang berbeda, mungkin perlu untuk mengoptimalkannya, sehingga Anda dapat mencakup semua yang beragam menggunakan kasing secara efisien. Meski begitu, kebutuhan akan kinerja harus selalu diimbangi dengan kebutuhan akan keterbacaan, pemeliharaan, keanggunan, ekstensibilitas, dan sebagainya.
sumber
Secara pribadi, sebagaimana dibahas dalam utas sebelumnya , saya tidak percaya optimasi awal buruk dalam situasi di mana Anda tahu Anda akan mengalami masalah kinerja. Sebagai contoh, saya menulis pemodelan permukaan dan perangkat lunak analisis, di mana saya secara teratur berurusan dengan puluhan juta entitas. Perencanaan untuk kinerja optimal pada tahap desain jauh lebih unggul daripada optimasi akhir dari desain yang lemah.
Hal lain yang perlu dipertimbangkan adalah bagaimana aplikasi Anda akan berkembang di masa depan. Jika Anda menganggap bahwa kode Anda akan berumur panjang, mengoptimalkan kinerja pada tahap desain juga merupakan ide bagus.
Dalam pengalaman saya, optimasi yang terlambat memberikan imbalan yang sangat sedikit dengan harga tinggi. Mengoptimalkan pada tahap desain, melalui pemilihan algoritma dan penyesuaian, adalah cara yang lebih baik. Bergantung pada profiler untuk memahami cara kerja kode Anda bukan cara yang bagus untuk mendapatkan kode kinerja tinggi, Anda harus mengetahuinya sebelumnya.
sumber
Sebenarnya saya mengetahui bahwa non-optimasi dini lebih sering menjadi akar dari semua kejahatan.
Ketika orang menulis perangkat lunak pada awalnya akan mengalami masalah, seperti ketidakstabilan, fitur terbatas, kegunaan yang buruk dan kinerja yang buruk. Semua ini biasanya diperbaiki, ketika perangkat lunak matang.
Semua ini, kecuali kinerja. Sepertinya tidak ada yang peduli dengan kinerja. Alasannya sederhana: jika perangkat lunak crash, seseorang akan memperbaiki bug dan hanya itu, jika fitur hilang, seseorang akan mengimplementasikannya dan selesai, jika perangkat lunak memiliki kinerja buruk itu dalam banyak kasus bukan karena hilang optimasi mikro, tetapi karena desain yang buruk dan tidak ada yang akan menyentuh desain perangkat lunak. PERNAH.
Lihatlah Bochs. Ini sangat lambat. Apakah akan lebih cepat? Mungkin, tetapi hanya dalam kisaran beberapa persen saja. Ini tidak akan pernah mendapatkan kinerja yang sebanding dengan perangkat lunak virtualisasi seperti VMWare atau VBox atau bahkan QEMU. Karena desainnya lambat!
Jika masalah suatu perangkat lunak adalah lambat, maka karena itu SANGAT lambat dan ini hanya dapat diperbaiki dengan meningkatkan kinerja banyak orang. + 10% tidak akan membuat perangkat lunak menjadi cepat cepat. Dan Anda biasanya tidak akan mendapatkan lebih dari 10% dengan optimasi nanti.
Jadi, jika kinerja APA PUN penting untuk perangkat lunak Anda, Anda harus memperhitungkannya sejak awal, saat mendesainnya, alih-alih berpikir "oh ya, ini lambat, tapi kami bisa memperbaikinya nanti". Karena kamu tidak bisa!
Saya tahu itu tidak benar-benar cocok dengan kasus spesifik Anda, tetapi menjawab pertanyaan umum "Apakah optimasi prematur benar-benar akar dari semua kejahatan?" - dengan TIDAK jelas.
Setiap optimasi, seperti fitur apa pun, dll. Harus dirancang dengan hati-hati dan diimplementasikan dengan hati-hati. Dan itu termasuk evaluasi biaya dan manfaat yang tepat. Jangan optimalkan algoritme untuk menyimpan beberapa siklus di sana-sini, saat tidak membuat perolehan kinerja yang terukur.
Sama seperti contoh: Anda dapat meningkatkan kinerja fungsi dengan menggarisbawahi, mungkin menghemat beberapa siklus, tetapi pada saat yang sama Anda mungkin meningkatkan ukuran executable Anda, meningkatkan kemungkinan TLB dan cache misses menghabiskan ribuan siklus atau bahkan operasi paging, yang akan mematikan kinerja sepenuhnya. Jika Anda tidak memahami hal-hal ini, "optimasi" Anda dapat berubah menjadi buruk.
Optimasi bodoh lebih jahat daripada optimasi "prematur", namun keduanya masih lebih baik daripada non-optimasi prematur.
sumber
Ada dua masalah dengan PO: pertama, waktu pengembangan digunakan untuk pekerjaan yang tidak penting, yang dapat digunakan untuk menulis lebih banyak fitur atau memperbaiki lebih banyak bug, dan kedua, rasa aman palsu bahwa kode berjalan efisien. PO sering melibatkan pengoptimalan kode yang tidak akan menjadi botol-leher, sementara tidak memperhatikan kode yang akan melakukannya. Bit "prematur" berarti optimasi dilakukan sebelum masalah diidentifikasi menggunakan pengukuran yang tepat.
Jadi pada dasarnya, ya, ini kedengarannya seperti pengoptimalan prematur, tapi saya tidak perlu mundur kecuali memperkenalkan bug - lagipula, sudah dioptimalkan sekarang (!)
sumber
Saya percaya itulah yang oleh Mike Cohn disebut 'pelapisan emas' kode - yaitu menghabiskan waktu untuk hal-hal yang bisa menyenangkan tetapi tidak perlu.
Dia menyarankan untuk tidak melakukannya.
PS 'Gold-plating' bisa menjadi lonceng-dan-peluit jenis fungsionalitas bijaksana. Ketika Anda melihat kode itu mengambil bentuk optimasi yang tidak perlu, kelas 'masa depan-bukti' dll.
sumber
Karena tidak ada masalah dalam memahami kode, maka kasus ini dapat dianggap sebagai pengecualian.
Tetapi secara umum optimasi mengarah pada kode yang kurang dapat dibaca dan kurang dimengerti dan harus diterapkan hanya jika diperlukan. Contoh sederhana - jika Anda tahu bahwa Anda harus mengurutkan hanya beberapa elemen - maka gunakan BubbleSort. Tetapi jika Anda mencurigai bahwa unsur-unsurnya dapat meningkat dan Anda tidak tahu berapa banyak, maka mengoptimalkan dengan QuickSort (misalnya) bukanlah kejahatan, tetapi suatu keharusan. Dan ini harus dipertimbangkan selama desain program.
sumber
Saya telah menemukan bahwa masalah dengan optimasi prematur kebanyakan terjadi ketika menulis ulang kode yang ada menjadi lebih cepat. Saya bisa melihat bagaimana mungkin menjadi masalah untuk menulis beberapa optimasi berbelit-belit di tempat pertama, tetapi kebanyakan saya melihat optimasi prematur membesarkan kepala jelek dalam memperbaiki apa yang tidak (diketahui) rusak.
Dan contoh terburuk dari ini adalah setiap kali saya melihat seseorang menerapkan kembali fitur dari perpustakaan standar. Itu adalah bendera merah utama. Seperti, saya pernah melihat seseorang menerapkan rutinitas khusus untuk manipulasi string karena dia khawatir bahwa perintah bawaan terlalu lambat.
Ini menghasilkan kode yang lebih sulit untuk dipahami (buruk) dan menghabiskan banyak waktu untuk bekerja yang mungkin tidak berguna (buruk).
sumber
Dari sudut pandang yang berbeda, ini adalah pengalaman saya bahwa sebagian besar programmer / pengembang tidak berencana untuk sukses dan "prototipe" hampir selalu menjadi Rilis 1.0. Saya memiliki pengalaman langsung dengan 4 produk asli yang terpisah di mana front-end yang berkelas, seksi, dan sangat fungsional (pada dasarnya UI) menghasilkan adopsi dan antusiasme pengguna yang tersebar luas. Di masing-masing produk ini, masalah kinerja mulai merambat dalam waktu yang relatif singkat (1 hingga 2 tahun) terutama ketika pelanggan yang lebih besar dan lebih menuntut, mulai mengadopsi produk. Segera kinerja mendominasi daftar masalah, meskipun pengembangan fitur baru mendominasi daftar prioritas manajemen. Pelanggan menjadi semakin frustrasi ketika setiap rilis menambahkan fitur baru yang terdengar hebat tetapi hampir tidak dapat diakses karena masalah kinerja.
Jadi, desain yang sangat mendasar dan kelemahan implementasi yang kurang atau tidak ada perhatian dalam "tipe proto" menjadi batu sandungan utama untuk kesuksesan jangka panjang dari produk (dan perusahaan).
Demo pelanggan Anda mungkin terlihat dan berkinerja bagus di laptop Anda dengan XML DOM, SQL Express, dan banyak data cache di sisi klien. Sistem produksi mungkin akan menyebabkan crash jika Anda berhasil.
Pada tahun 1976 kami masih memperdebatkan cara optimal menghitung akar kuadrat atau menyortir array besar dan pepatah Don Knuth diarahkan pada kesalahan fokus pada mengoptimalkan semacam itu rutin tingkat rendah di awal proses desain daripada berfokus pada pemecahan masalah. dan kemudian mengoptimalkan wilayah kode yang dilokalkan.
Ketika seseorang mengulangi pepatah sebagai alasan untuk tidak menulis kode efisien (C ++, VB, T-SQL atau lainnya), atau untuk tidak mendesain penyimpanan data dengan benar, atau untuk tidak mempertimbangkan arsitektur kerja bersih, maka IMO mereka hanya menunjukkan pemahaman yang sangat dangkal tentang sifat nyata dari pekerjaan kami. sinar
sumber
Saya kira itu tergantung pada bagaimana Anda mendefinisikan "prematur". Membuat fungsionalitas tingkat rendah dengan cepat ketika Anda menulis tidak secara inheren jahat. Saya pikir itu salah paham dari kutipan. Terkadang saya berpikir bahwa kutipan dapat dilakukan dengan kualifikasi yang lebih banyak. Saya akan mengulangi komentar m_pGladiator tentang keterbacaan.
sumber
Jawabannya adalah, tergantung. Saya akan berpendapat bahwa efisiensi adalah masalah besar untuk jenis pekerjaan tertentu, seperti permintaan basis data yang kompleks. Dalam banyak kasus lain, komputer menghabiskan sebagian besar waktunya menunggu input pengguna sehingga mengoptimalkan sebagian besar kode paling hanya merupakan usaha yang sia-sia dan paling buruk kontraproduktif.
Dalam beberapa kasus Anda dapat merancang untuk efisiensi atau kinerja (dirasakan atau nyata) - memilih algoritma yang sesuai atau merancang antarmuka pengguna sehingga operasi mahal tertentu terjadi di latar belakang misalnya. Dalam banyak kasus, pembuatan profil atau operasi lain untuk menentukan hotspot akan memberi Anda manfaat 10/90.
Salah satu contoh yang dapat saya jelaskan adalah model data yang pernah saya lakukan untuk sistem manajemen kasus pengadilan yang memiliki sekitar 560 tabel di dalamnya. Ini mulai dinormalisasi ('dinormalisasi indah' seperti yang dikatakan oleh konsultan dari perusahaan besar-5 tertentu) dan kami hanya perlu memasukkan empat item data yang dinormalisasi di dalamnya:
Satu tampilan terwujud untuk mendukung layar pencarian
Satu tabel terpicu-dipelihara untuk mendukung layar pencarian lain yang tidak dapat dilakukan dengan tampilan terwujud.
Satu tabel pelaporan dinormalisasi (ini hanya ada karena kami harus mengambil beberapa laporan throughput ketika proyek gudang data dikalengkan)
Satu tabel terpicu-dipelihara untuk antarmuka yang harus mencari yang paling baru dari sejumlah besar peristiwa yang berbeda dalam sistem.
Ini adalah (pada saat itu) proyek J2EE terbesar di Australasia - lebih dari 100 tahun waktu pengembang - dan memiliki 4 item yang tidak normal dalam skema database, salah satunya tidak benar-benar termasuk di sana.
sumber
Optimalisasi prematur bukanlah akar dari SEMUA kejahatan, itu sudah pasti. Namun ada beberapa kelemahannya:
Alih-alih optimasi prematur, orang dapat melakukan tes visibilitas awal, untuk melihat apakah ada kebutuhan aktual untuk optimasi yang lebih baik.
sumber
Sebagian besar dari mereka yang mematuhi "PMO" (kutipan parsial, yaitu) mengatakan bahwa optimisasi harus didasarkan pada pengukuran dan pengukuran tidak dapat dilakukan sampai pada akhir.
Ini juga pengalaman saya dari pengembangan sistem besar bahwa pengujian kinerja dilakukan pada akhir, karena pengembangan hampir selesai.
Jika kita mengikuti "nasihat" orang-orang ini, semua sistem akan sangat lambat. Mereka akan menjadi mahal juga karena kebutuhan perangkat keras mereka jauh lebih besar daripada yang dibayangkan semula.
Saya telah lama menganjurkan melakukan tes kinerja pada interval reguler dalam proses pengembangan: ini akan menunjukkan keberadaan kode baru (di mana sebelumnya tidak ada) dan keadaan kode yang ada.
Gagasan hewan peliharaan lainnya adalah menginstruksikan perangkat lunak pada level blok fungsi. Saat sistem dijalankan, ia mengumpulkan informasi tentang waktu eksekusi untuk blok fungsi. Ketika pemutakhiran sistem dilakukan, dapat ditentukan blok fungsi apa yang dilakukan seperti yang mereka lakukan pada rilis sebelumnya dan yang telah memburuk. Pada layar perangkat lunak, data kinerja dapat diakses dari menu bantuan.
Lihatlah bagian luar biasa ini tentang apa yang PMO mungkin atau tidak mungkin maksudkan.
sumber