Kapan optimisasi tidak prematur dan karenanya tidak jahat?

75

"Optimalisasi prematur adalah akar dari semua kejahatan" adalah sesuatu yang hampir semua dari kita telah dengar / baca. Apa yang saya ingin tahu seperti apa optimasi tidak prematur, yaitu pada setiap tahap pengembangan perangkat lunak (desain tingkat tinggi, desain detail, implementasi tingkat tinggi, implementasi rinci dll) sejauh mana optimasi dapat kita pertimbangkan tanpa menyeberang ke sisi gelap.

Gaurav
sumber

Jawaban:

116

Ketika Anda mendasarkannya dari pengalaman? Bukan jahat. "Setiap kali kita melakukan X, kita mengalami kinerja yang brutal. Mari kita rencanakan untuk mengoptimalkan atau menghindari X sepenuhnya saat ini."

Kapan itu relatif tidak menyakitkan? Bukan jahat. "Menerapkan ini sebagai Foo atau Bar akan mengambil banyak pekerjaan, tetapi secara teori, Bar harus jauh lebih efisien. Ayo Buang itu."

Ketika Anda menghindari algoritma jelek yang akan sangat skala? Bukan jahat. "Pimpinan teknologi kami mengatakan algoritma pemilihan jalur yang kami usulkan berjalan dalam waktu faktorial; Saya tidak yakin apa artinya itu, tetapi dia menyarankan agar kami melakukan seppuku bahkan untuk mempertimbangkannya. Mari kita pertimbangkan sesuatu yang lain."

Kejahatan datang dari menghabiskan banyak waktu dan masalah pemecahan energi yang Anda tidak tahu sebenarnya ada. Ketika masalah benar-benar ada, atau ketika masalah psudo hantu mungkin diselesaikan dengan murah, kejahatan menghilang.


Steve314 dan Matthieu M. meningkatkan poin dalam komentar yang seharusnya dipertimbangkan. Pada dasarnya, beberapa jenis optimisasi "tanpa rasa sakit" sama sekali tidak sepadan karena peningkatan kinerja sepele yang mereka tawarkan tidak sebanding dengan kebingungan kode, mereka menduplikasi peningkatan yang telah dilakukan oleh kompiler, atau keduanya. Lihat komentar untuk beberapa contoh bagus dari non-perbaikan yang terlalu pintar-setengahnya.

BlairHippo
sumber
22
Kadang-kadang, memecahkan masalah hantu dengan mudah masih agak jahat, karena dapat mengakibatkan lebih sulit untuk membaca, lebih sulit untuk mempertahankan kode. Tidak jauh lebih sulit (atau itu bukan solusi yang mudah), tetapi mungkin kadang-kadang masih relevan. Contohnya mungkin menggunakan trik bitwise pintar yang tidak akan dikenali oleh beberapa orang, dan kompiler mana yang mungkin akan berlaku jika itu berguna.
Steve314
26
Saya setuju dengan Steve di sini, kadang-kadang "optimasi" sama sekali tidak sepadan, terutama karena kompiler sangat bagus. Contoh jika itidak ditandatangani, i / 2dapat diganti oleh i >> 1. Lebih cepat. Tetapi juga lebih samar (tidak semua orang akan melihat efeknya, bahkan mereka yang kehilangan waktu). Tetapi yang terburuk adalah kompiler akan tetap melakukannya, jadi mengapa mengaburkan kode sumber;)?
Matthieu M.
19
@ Larry: Saya tidak, jadi saya kira itu adalah contoh yang bagus.
Joris Meys
18
Dalam pandangan saya, optimisasi, bahkan yang sederhana, juga harus dianggap jahat jika berdampak pada kesesuaian / pemeliharaan kode dan tidak didasarkan pada pengukuran kinerja aktual.
Bart van Ingen Schenau
14
@ Matthew: Ajari mereka apa? Trik kotor dan tidak perlu? Mengapa? Jika profil menunjukkan bahwa a i/2memang hot spot dan (tidak dapat dipercaya, tapi mari kita asumsikan) i>>1membuatnya lebih cepat, maka lakukan, dan beri komentar bahwa profil ini menunjukkan bahwa ini lebih cepat. Jika ini memang diperlukan di mana saja (yang saya ragu, karena, seperti yang dikatakan Matthieu, kompiler harus cukup pintar untuk melakukan ini sendiri), pemula akan belajar sesuatu, jika tidak (yang kemungkinan), mengapa Anda ingin menghubungkan kepala mereka dengan cerita rakyat yang tidak dibutuhkan?
sbi
38

Kode aplikasi seharusnya hanya sebagus yang diperlukan, tetapi kode perpustakaan harus sebaik mungkin, karena Anda tidak pernah tahu bagaimana perpustakaan Anda akan digunakan. Jadi ketika Anda menulis kode pustaka, itu harus bagus di semua aspek, baik itu kinerja, ketahanan, atau kategori lainnya.

Selain itu, Anda perlu memikirkan kinerja saat merancang aplikasi dan memilih algoritma . Jika tidak dirancang untuk menjadi performan, tidak ada tingkat peretasan yang dapat menjadikannya berkinerja setelahnya dan tidak ada optimasi mikro yang melebihi algoritma yang unggul.

sbi
sumber
5
Kode perpustakaan harus mendokumentasikan apakah berusaha "sebaik mungkin", atau apa tujuannya. Kode tidak harus benar-benar optimal agar bermanfaat, asalkan konsumen hanya menggunakannya saat yang tepat.
supercat
1
Maaf, tapi "bersikap baik dalam semua aspek" kedengarannya mencurigakan seperti rekayasa berlebihan. Plus, itu mungkin tidak realistis - hidup selalu tentang pengorbanan.
sleske
1
+1 untuk menekankan fase desain; jika Anda sengaja menimbang manfaatnya, itu bukan prematur.
Nathan Tuggy
Sebaliknya, jika Anda tidak pernah tahu bagaimana perpustakaan Anda akan digunakan, Anda tidak tahu apakah menghabiskan waktu untuk meningkatkannya memiliki nilai bisnis sama sekali. Jadi itu bukan argumen.
RemcoGerlich
25

optimasi seperti apa yang tidak prematur

Jenis yang datang sebagai hasil dari masalah yang diketahui.

George Marian
sumber
17

Kapan optimisasi tidak prematur dan karenanya tidak jahat?

Sulit mengatakan yang baik dan yang jahat. Siapa yang berhak? Jika kita melihat alam, tampaknya kita diprogram untuk bertahan hidup dengan definisi luas tentang "bertahan hidup" yang mencakup mewariskan gen kita kepada keturunan.

Jadi saya akan mengatakan, paling tidak sesuai dengan fungsi dasar dan pemrograman kami, optimasi itu tidak jahat ketika sejalan dengan tujuan reproduksi. Bagi para pria, ada yang berambut pirang, berambut cokelat, berambut merah, banyak yang cantik. Untuk cewek, ada cowok, dan beberapa dari mereka tampaknya baik-baik saja.

Mungkin kita harus mengoptimalkan ke arah tujuan itu, dan ada baiknya menggunakan profiler. Profiler akan membiarkan Anda memprioritaskan pengoptimalan dan waktu Anda lebih efektif selain memberi Anda informasi terperinci tentang hotspot dan mengapa hal itu terjadi. Ini akan memberi Anda lebih banyak waktu luang yang dihabiskan untuk reproduksi dan pengejarannya.


sumber
3
Sangat menyegarkan melihat seseorang membawa makanan segar ke berangan tua ini. Yang diperlukan hanyalah membaca seluruh kutipan Knuth, dan bukan hanya satu kalimat, eh?
Robert Harvey
1
@RobertHarvey Saya punya sedikit kesal di sana - karena begitu banyak yang mengutip hanya satu kalimat, dan begitu banyak info kontekstual yang penting akhirnya hilang dalam proses. Saya tidak yakin itu jawaban yang bagus karena saya mendapat sedikit ranty. :-D
14

The kutipan penuh mendefinisikan ketika optimasi tidak prematur:

Seorang programmer yang baik tidak akan terbuai oleh kepuasan dengan alasan seperti itu, ia akan bijaksana untuk melihat dengan cermat kode kritis; tetapi hanya setelah kode itu diidentifikasi . [penekanan milikku]

Anda dapat mengidentifikasi kode kritis dalam banyak cara: struktur data kritis atau algoritma (misalnya banyak digunakan atau "inti" proyek) dapat memberikan optimasi besar, banyak optimasi kecil diidentifikasi melalui profiler, dan sebagainya.

Fred Nurk
sumber
6
Ya ... Semuanya baik dan bagus untuk mencukur 90% dari waktu panggilan fungsi acak dilakukan, tapi mungkin Anda akan mendapatkan dampak yang lebih besar dengan melihat kode tempat aplikasi Anda menghabiskan 80% waktunya dan mengurangi beberapa persen di sana.
11

Anda harus selalu memilih solusi "cukup baik" dalam semua kasus berdasarkan pengalaman Anda.

Pepatah pengoptimalan mengacu pada penulisan "kode yang lebih kompleks daripada 'cukup baik' untuk membuatnya lebih cepat" sebelum benar-benar mengetahui bahwa itu perlu, karenanya membuat kode lebih kompleks daripada yang diperlukan. Kompleksitas adalah yang membuat segalanya sulit, jadi itu bukan hal yang baik.

Ini berarti bahwa Anda tidak boleh memilih "super kompleks" file 100 Gb dengan secara swap transparan ke disk "menyortir rutin ketika semacam sederhana akan dilakukan, tetapi Anda juga harus membuat pilihan yang baik untuk jenis sederhana di tempat pertama. Pilih Bubble Sort secara buta atau "pilih semua entri secara acak dan lihat apakah semuanya sesuai. Ulangi." Jarang baik.


sumber
3

Aturan umum saya: jika Anda tidak yakin Anda akan perlu optimasi, anggap Anda tidak. Tetapi perlu diingat ketika Anda perlu mengoptimalkan. Ada beberapa masalah yang bisa Anda ketahui di muka. Ini biasanya melibatkan pemilihan algoritma dan struktur data yang baik. Misalnya, jika Anda perlu memeriksa keanggotaan dalam koleksi, Anda dapat yakin bahwa Anda akan memerlukan beberapa jenis struktur data yang ditetapkan.

Jason Baker
sumber
3

Dalam pengalaman saya, pada tahap implementasi terperinci jawabannya terletak pada profiling kode. Penting untuk mengetahui apa yang harus lebih cepat dan apa yang dapat diterima dengan cepat.

Penting juga untuk mengetahui di mana sebenarnya hambatan kinerja - mengoptimalkan bagian dari kode yang hanya membutuhkan 5% dari total waktu untuk menjalankan tidak akan ada gunanya.

Langkah 2 dan 3 menjelaskan optimasi non-prematur:

  1. Buat itu bekerja
  2. Uji. Tidak cukup cepat? Profil itu .
  3. Dengan menggunakan data dari langkah 2, optimalkan bagian kode yang paling lambat.
Gorgi Kosev
sumber
Anda lupa langkah 0, yaitu: arsitek aplikasi dengan benar sehingga Anda dapat mengharapkan kinerja yang wajar dari awal.
Robert Harvey
Saya hanya berbicara tentang fase implementasi terperinci.
Gorgi Kosev
1
Saya mempertanyakan langkah # 3 - sangat sering jawaban terbaik adalah mencari pendekatan yang berbeda sehingga Anda tidak melakukan sedikit kode yang lambat di tempat pertama.
Loren Pechtel
1
Pilih struktur data yang tepat.
jasonk
3

Ini bukan optimasi ketika memilih hal-hal yang sulit diubah misalnya: platform perangkat keras.

Memilih struktur data adalah contoh yang baik - penting untuk memenuhi persyaratan (kinerja) fungsional dan non-fungsional. Tidak mudah diubah dan itu akan mendorong semua hal lain di aplikasi Anda. Struktur data Anda mengubah algoritma apa yang tersedia dll.

jasonk
sumber
3

Saya hanya tahu satu cara untuk menjawab pertanyaan ini, dan itu adalah untuk mendapatkan pengalaman dalam penyempurnaan kinerja. Itu berarti - menulis program, dan setelah ditulis, temukan speedup di dalamnya, dan lakukan iteratif. Ini salah satu contohnya.

Inilah kesalahan yang dibuat kebanyakan orang: Mereka mencoba mengoptimalkan program sebelum benar-benar menjalankannya. Jika mereka telah mengambil kursus pemrograman (dari seorang profesor yang tidak benar-benar memiliki banyak pengalaman praktis) mereka akan memiliki kacamata berwarna O-besar, dan mereka akan berpikir itu tentang semua itu . Ini semua masalah yang sama, optimasi sebelumnya. **

Seseorang berkata: Pertama, perbaiki, lalu perbaiki. Mereka benar.

Tetapi sekarang untuk si penendang: Jika Anda telah melakukan ini beberapa kali, Anda mengenali hal-hal konyol yang Anda lakukan sebelumnya yang menyebabkan masalah kecepatan, jadi Anda secara naluriah menghindarinya. (Hal-hal seperti membuat struktur kelas Anda terlalu berat, dibanjiri notifikasi, ukuran panggilan fungsi yang membingungkan dengan biaya waktunya, daftarnya terus-menerus ...) Anda secara naluriah menghindarinya, tetapi tebak seperti apa kelihatannya bagi yang kurang- berpengalaman: optimasi prematur!

Jadi debat konyol ini berlangsung terus-menerus :)

** Hal lain yang mereka katakan adalah Anda tidak perlu khawatir lagi, karena kompiler sangat bagus, dan mesin sangat cepat saat ini. (KIWI - Kill It With Iron.) Tidak ada peningkatan kecepatan perangkat keras atau sistem eksponensial (dilakukan oleh insinyur pekerja keras yang sangat pintar) yang mungkin dapat mengompensasi perlambatan perangkat lunak eksponensial (dilakukan oleh programmer yang berpikir seperti ini).

Mike Dunlavey
sumber
2

Ketika persyaratan atau pasar secara khusus memintanya.

Misalnya kinerja adalah persyaratan dalam sebagian besar aplikasi keuangan karena latensi rendah sangat penting. Bergantung pada sifat instrumen yang diperdagangkan, pengoptimalan dapat berubah dari menggunakan algoritme non-penguncian dalam bahasa tingkat tinggi hingga menggunakan bahasa tingkat rendah dan bahkan ekstrem - menerapkan algoritme pencocokan pesanan pada perangkat keras itu sendiri (menggunakan FPGA misalnya ).

Contoh lain adalah beberapa jenis perangkat yang disematkan. Ambil contoh rem ABS; pertama ada keamanan, ketika Anda menekan istirahat mobil harus melambat. Tetapi ada juga kinerja, Anda tidak ingin ada penundaan ketika Anda mencapai istirahat.

m3th0dman
sumber
0

Kebanyakan orang akan menyebut optimasi prematur, jika Anda mengoptimalkan sesuatu yang tidak menghasilkan "kegagalan lunak" (itu berfungsi tetapi masih tidak berguna) dari sistem karena kinerja.

Contoh dunia nyata.

  • Jika sort bubble saya membutuhkan 20ms untuk berjalan, mengoptimalkannya ke quicksort 1ms tidak akan meningkatkan utilitas keseluruhan dengan cara yang berarti meskipun ada peningkatan kinerja 2000%.

  • Jika sebuah halaman web membutuhkan 20 detik untuk memuat dan kami menguranginya menjadi 1 detik, ini dapat meningkatkan utilitas situs web dari 0 hingga hampir tak terbatas. Pada dasarnya sesuatu yang rusak karena terlalu lambat, kini bermanfaat.

Eric
sumber
Penting untuk dicatat bahwa jika jenis Anda dipanggil 1000 kali selama program Anda, mengoptimalkan dari 20 ms ke 1 ms adalah masalah besar.
Beefster
0

Apa jenis optimasi yang tidak prematur?

Optimasi yang memperbaiki masalah kinerja yang diketahui dengan aplikasi Anda, atau optimisasi yang memungkinkan aplikasi Anda memenuhi kriteria penerimaan yang ditentukan dengan baik.

Setelah diidentifikasi, beberapa waktu harus diambil untuk menetapkan perbaikan dan manfaat kinerja harus diukur.

(Yaitu bukan - "Saya pikir sedikit kode ini sepertinya bisa lambat, saya akan mengubah X untuk menggunakan Y sebagai gantinya dan itu akan lebih cepat").

Saya telah menemukan banyak "optimasi" prematur yang akhirnya membuat kode lebih lambat - dalam hal ini, saya menganggap prematur berarti 'tidak dipikirkan'. Kinerja harus diperbandingkan sebelum dan sesudah optimasi dan hanya kode yang benar-benar meningkatkan kinerja yang disimpan.

Padi
sumber
0

"Optimalisasi prematur adalah akar dari semua kejahatan" adalah sesuatu yang hampir semua dari kita telah dengar / baca

Benar. Sayangnya itu juga salah satu kutipan pemrograman yang paling banyak disalahgunakan sepanjang masa. Karena Donald Knuth menciptakan meme, ada baiknya menambahkan beberapa konteks asli dari kutipan:

Kita harus melupakan efisiensi kecil, katakanlah sekitar 97% dari waktu: optimasi prematur adalah akar dari semua kejahatan. Namun kita tidak boleh melewatkan peluang kita dalam 3% kritis itu. ... Seorang programmer yang baik ... akan bijaksana untuk melihat dengan cermat kode kritis; tetapi hanya setelah kode itu diidentifikasi. ... pengalaman universal programmer yang telah menggunakan alat pengukuran adalah bahwa tebakan intuisi mereka gagal

Perhatikan bahwa Knuth berbicara secara khusus tentang kecepatan eksekusi di runtime .

..Program menghabiskan banyak waktu memikirkan, atau mengkhawatirkan, kecepatan bagian nonkritis dari program mereka ..

Juga, ia menulis artikel pada 1974 ketika sumber daya mesin mana pun yang memiliki korelasi premium dan negatif antara kecepatan eksekusi dan rawatan program (kecepatan lebih tinggi - kurang dapat dirawat) mungkin lebih kuat dari sekarang.

OK, untuk menjawab pertanyaan Anda, menurut Donald Knuth, optimisasi BUKAN prematur jika itu memperbaiki hambatan kinerja serius yang telah diidentifikasi (diukur secara ideal dan ditunjukkan dengan tepat selama pembuatan profil).

Seperti yang saya katakan sebelumnya, "optimasi prematur" adalah salah satu meme yang paling banyak disalahgunakan, jadi jawabannya tidak akan lengkap tanpa beberapa contoh hal-hal yang bukan optimasi prematur tetapi terkadang diabaikan seperti itu:

  • kemacetan yang terlihat dengan mata telanjang dan dapat dihindari sebelum diperkenalkan seperti O (N ^ 2) jumlah bolak-balik ke database dengan N besar di mana O (1) alternatif ada

Lebih jauh bahkan tidak terkait dengan kecepatan eksekusi runtime:

Kola
sumber