Kembali ke "masa lalu yang indah," ketika kami akan menyalin shareware ke disket untuk teman-teman, kami juga menggunakan sedikit perakitan. Ada praktik umum "optimasi mikro," di mana Anda akan menatap dan menatap garis-garis perakitan sampai Anda menemukan cara untuk mengekspresikannya dalam satu instruksi yang lebih sedikit. Bahkan ada pepatah, yang secara matematis tidak mungkin, bahwa " Anda selalu dapat menghapus satu instruksi lagi. " Mengingat bahwa mengubah kinerja runtime oleh faktor konstan kecil bukanlah masalah utama untuk (kebanyakan) pemrograman saat ini, adalah pemrogram mentransfer mikro ini upaya optimasi di tempat lain?
Dengan kata lain, bisakah praktik terbaik dibawa ke keadaan ekstrem di mana praktik itu tidak lagi menambah nilai? Dan bukannya membuang-buang waktu?
Sebagai contoh: Apakah programmer membuang waktu untuk menggeneralisasi metode pribadi yang hanya dipanggil dari satu tempat? Apakah waktu terbuang mengurangi data kasus uji? Apakah programmer (masih) terlalu khawatir tentang pengurangan baris kode?
Ada dua contoh hebat dari apa yang saya cari di bawah ini: (1) Menghabiskan waktu untuk menemukan nama variabel yang tepat, bahkan mengganti nama semuanya; dan (2) Menghapus bahkan duplikasi kode kecil dan renggang.
Perhatikan bahwa ini berbeda dari pertanyaan " Apa yang Anda optimalkan? ", Karena saya bertanya apa yang tampaknya dipaksakan oleh pemrogram lain, dengan stigma pengoptimalan "mikro" ini, dan karenanya bukan penggunaan waktu yang produktif.
sumber
Jawaban:
Pemformatan kode
sumber
=
dan keempat untuk inisialisasi!Saya biasa menulis banyak assembler kembali pada hari itu. Bukan saja kompiler menjadi lebih baik, tetapi sebagian besar perangkat keras sekarang memiliki banyak logika yang dikhususkan untuk eksekusi kode yang out-of-order. Masalah mikro sebenarnya adalah penjadwalan, sebagian besar instruksi komputer mengambil beberapa jam mesin untuk menghasilkan hasil - dan beban memori yang meluputkan cache mungkin membutuhkan beberapa ratus! Jadi idenya adalah untuk menjadwalkan instruksi lain untuk melakukan sesuatu yang bermanfaat, alih-alih menunggu hasil. Dan mesin modern dapat mengeluarkan beberapa instruksi per periode jam. Setelah kami mulai mengeksekusi HW yang tidak sesuai pesanan, saya menemukan bahwa mencoba untuk mendapatkan kinerja yang hebat dengan hand coding menjadi permainan mug. Pertama HW rusak tidak akan menjalankan instruksi dalam pesanan Anda dibuat dengan hati-hati, arsitektur HW baru yang mewah telah mengurangi penalti cukup penjadwalan perangkat lunak yang tidak optimal sehingga kompiler biasanya dalam beberapa persen dari kinerja Anda. Saya juga menemukan bahwa kompiler sekarang menerapkan trik yang terkenal tetapi menghasilkan kompleksitas, seperti membuka gulungan, memuat bawah, pipelining perangkat lunak dll. Intinya, Anda harus bekerja sangat keras, lewati beberapa trik ini dan kompiler mengalahkan Anda. Gunakan semuanya dan jumlah instruksi assembler yang Anda butuhkan bertambah beberapa kali lipat!
Mungkin bahkan lebih penting, sebagian besar masalah kinerja, bukan tentang tingkat masalah instruksi, tetapi memasukkan data ke dalam CPU. Seperti yang saya sebutkan di atas, latensi memori sekarang ratusan siklus, dan CPU dapat menjalankan beberapa instruksi per periode jam, jadi kecuali program-dan terutama struktur data dirancang sehingga tingkat hit cache sangat tinggi, microtuning pada instruksi level tidak akan memiliki hasil. Sama seperti tipe militer mengatakan taktik bicara amatir, logistik pro bicara. Pemrograman kinerja sekarang lebih dari 90% logistik (memindahkan data). Dan ini sulit untuk diukur, karena manajemen memori modern biasanya memiliki beberapa tingkat cache, dan halaman memori virtual ditangani oleh unit perangkat keras yang disebut TLB. Juga penyejajaran tingkat rendah dari alamat menjadi penting, karena transfer data aktual, tidak dalam satuan byte, atau bahkan panjang 64bit, tetapi mereka datang dalam satuan garis cache. Kemudian sebagian besar mesin modern memiliki perangkat keras yang mencoba memprediksi baris cache yang Anda lewatkan dalam waktu dekat dan mengeluarkan prefetch otomatis untuk memasukkannya ke dalam cache. Jadi kenyataannya adalah bahwa dengan model kinerja CPU modern begitu rumit sehingga hampir tidak dapat dimengerti. Bahkan simulator perangkat keras terperinci tidak akan pernah bisa menandingi logika chip yang tepat, sehingga penyetelan yang tepat tidak mungkin dilakukan lagi.
Masih ada tempat untuk beberapa kode tangan. Pustaka matematika (seperti fungsi exp), seperti operasi aljabar linier yang lebih penting (seperti matriks berlipat ganda) masih biasanya dikodekan dengan tangan oleh para ahli yang bekerja untuk vendor perangkat keras (yaitu Intel atau AMD, atau IBM), tetapi mereka mungkin hanya perlu beberapa programmer assembler kedudukan tertinggi per mega-komputer corp.
sumber
float
. Untuk beberapa alasan saya tidak dapat mengerti, banyak orang melihat bahwa ini adalah hal yang baik.Saya kadang-kadang menghabiskan (buang?) Waktu ketika memilih nama baik untuk variabel atau metode sehingga tidak hanya deskriptif tetapi juga memiliki gaya bahasa yang baik.
Ini sedikit lebih jauh ketika saya mencoba untuk menempatkan seluruh karya (program) ke dalam gaya bahasa yang sama. Kadang pendapat saya berubah dan saya merevisi buku itu. :)
Tidak, itu membutuhkan banyak waktu. Agak jarang. Tapi saya suka menjaga tata bahasa yang baik dalam program saya.
sumber
Kompleksitas waktu. Saya menghabiskan terlalu banyak waktu untuk mengoptimalkan hal-hal untuk kinerja kasus terburuk pada skala yang urutan besarnya lebih besar daripada apa pun yang saya tahu program akan bertemu secara realistis.
Saya terlalu obsesif untuk melepaskan tulang 'tapi itu bisa tumbuh sebesar itu', bahkan ketika keputusan desain lainnya menghalangi hal itu dari terjadi secara realistis.
Namun, dalam pembelaan saya, seandainya yang tidak realistis menjadi kenyataan .. optimalisasi sebenarnya bukan 'mikro' lagi. Catatan, saya tidak mengatakan tidak mungkin , tetapi tidak realistis .
Tentu saja, persyaratan diutamakan.
sumber
Saya pikir saya sudah menghabiskan waktu berminggu-minggu untuk mengutak-atik handler pengecualian Java.
Ini banyak pekerjaan untuk kode yang gagal dua atau tiga kali per tahun. Haruskah ini menjadi peringatan atau info? Kesalahan atau fatal? Apakah ini benar-benar fatal, prosesnya akan muncul kembali dalam lima menit? Apakah ini benar-benar peringatan jika semuanya masih dalam kondisi standar?
Banyak pusar yang memandang dan berdiskusi tentang sifat kesalahan IO. Jika Anda tidak dapat membaca file melalui jaringan, apakah itu kesalahan file atau kesalahan jaringan? Dan seterusnya.
Pada satu titik saya mengganti semua string concat dengan
String.format
sehingga kesalahan file tahunan tidak menghasilkan objek tambahan di heap. Itu sia-sia.sumber
Saya kira saya terlalu khawatir dengan LOC. Tidak begitu banyak LOC itu sendiri, tetapi lebih pada jumlah pernyataan dan bahkan lebih banyak lagi pernyataan duplikat. Saya alergi terhadap kode rangkap. Secara umum saya suka refactoring, tapi saya kira sekitar 50% dari apa yang saya lakukan tidak membuat kode lebih baik.
sumber
Membaca file baris demi baris alih-alih hanya membaca seluruh baris menjadi sebuah string dan memproses string dalam satu waktu.
Tentu, ini membuat perbedaan dalam kecepatan eksekusi tetapi jarang sepadan dengan baris kode tambahan. Itu membuat kode jauh lebih sedikit perawatan dan meningkatkan ukuran kode.
Ya, ini mungkin tidak masuk akal jika file tersebut 3GB besar tetapi sebagian besar file tidak sebesar itu (setidaknya bukan yang saya kerjakan ;-)).
sumber
Ketika saya sedang menulis bahasa assembly, masuk akal untuk memeriksa byte dan siklus, tapi itu sudah lama sekali dan kompiler telah datang jauh sejak saat itu. Saya tidak akan mencoba untuk mengoptimalkan secara manual sekarang.
Demikian pula, ketika saya beralih ke menulis dalam C itu cukup mudah untuk melakukan pekerjaan yang lebih baik daripada kompiler C, tetapi setiap tahun Borland atau Microsoft atau seseorang akan merilis yang baru dan yang lebih baik yang menendang yang sebelumnya di sekitar ruangan. Saya mulai memperhatikan kode perakitan aktual yang dipancarkan oleh kompiler dan, menggantung jika tidak menulis beberapa kode yang bagus dan ketat, membuka gulungan loop, memindahkan variabel di luar loop, dll.
Sekarang, saya menulis dalam banyak bahasa yang lebih tinggi seperti Perl, Python dan Ruby. Saya menggunakan beberapa trik kompiler di depan, seperti loop membuka gulungan jika itu masuk akal, memindahkan variabel statis di luar loop, dll., Tapi saya tidak terlalu khawatir tentang hal itu karena CPU sedikit lebih cepat sekarang. Jika suatu aplikasi tampaknya diseret secara tidak terduga maka saya akan menggunakan profiler dan melihat apa yang dapat saya temukan, dan kemudian jika sesuatu dapat diperbaiki saya akan mulai membuat tolok ukur berbagai cara yang dapat saya pikirkan untuk melakukan sesuatu lebih cepat, dan kemudian lihat bagaimana itu meningkat.
Secara umum saya mencoba untuk menjadi pintar tentang bagaimana saya menulis kode, berdasarkan pengalaman bertahun-tahun.
sumber
Pengoptimalan mikro: meningkatkan kinerja hal-hal tunggal yang dapat diparalelkan atau yang dapat ditingkatkan dengan perangkat keras baru.
Jika ada sesuatu yang lambat pada komputer dari 10 tahun yang lalu, solusi yang lebih murah mungkin untuk membeli komputer yang lebih baru, lebih cepat, daripada membuang waktu programmer mengoptimalkan. Fokus besar optimasi yang dipertimbangkan adalah mencari cara untuk menggunakan 8 core yang bisa Anda dapatkan hari ini, atau 64 core yang bisa Anda dapatkan dalam beberapa tahun, alih-alih merasa kesal tentang minutia seperti biaya tambahan sampah koleksi.
sumber
Mikro-optimasi dalam hal kinerja runtime hampir tidak menjadi masalah tertutup bahkan hari ini (walaupun mungkin kurang umum). Saya kadang-kadang harus menjelaskan kepada orang-orang bahwa overhead mengalokasikan objek tambahan setiap permintaan atau menambahkan panggilan fungsi tambahan dapat diabaikan.
Selain itu, saya juga melihat programmer mengoptimalkan mikro untuk kesederhanaan (termasuk saya sendiri). Saya belum bekerja di suatu tempat yang saya tidak perlu menjelaskan perbedaan antara kesederhanaan dan kesederhanaan.
sumber
programmers.
=programmers.stackexchange.com
berbeda dari setiap tempat Anda bekerja di mana Anda harus menjelaskan perbedaan antara kedua konsep ini? Tolong jelaskan perbedaannya.Saya mendukung prinsip jangan-optimalkan-kecuali-benar-benar-diperlukan. Dan saya semua untuk prinsip profil-pertama. Dan pada prinsipnya, saya hanya akan mengoptimalkan sesuatu yang akan membuat perbedaan yang dibutuhkan.
Itu pada prinsipnya. Tapi prinsip adalah pembohong.
Saya memiliki kebiasaan merawat fungsi-fungsi di perpustakaan yang sering digunakan yang saya pikir akan banyak digunakan dalam loop batin. Dan kemudian, ketika Anda melihat sesuatu di fungsi lain, itu tidak begitu sering digunakan ...
Oh - dan kemudian ada logika "Saya sedang menulis itu - tentu saja itu adalah perpustakaan yang penting".
Oh - dan BTW. Saya belum pernah menggunakan profiler untuk memandu optimasi. Tidak memiliki akses ke iklan, dan tidak pernah cukup membangun motivasi untuk mencari tahu gprof.
Pada dasarnya, saya munafik. Prinsip-prinsip ini berlaku untuk orang lain, tetapi saya terlalu takut pada seseorang yang mengatakan "tetapi mengapa Anda menulisnya dengan cara yang lambat dan jelek?" jadi saya tidak akan pernah bisa menerapkannya dengan benar pada diri saya sendiri.
Tapi aku tidak seburuk yang kulakukan di sini. Dan saya benar-benar kebal terhadap penipuan diri sendiri, jadi Anda tahu saya benar tentang itu!
EDIT
Saya harus menambahkan - salah satu hang-up bodoh utama saya adalah panggilan overhead. Tidak di mana-mana, tentu saja, tetapi dalam kasus-kasus yang saya-pikir-itu-akan-digunakan-banyak-di-dalam-loop (di mana saya tidak punya bukti objektif masalah). Saya telah menulis kode berbasis offset jahat untuk menghindari membuat panggilan metode virtual lebih dari sekali. Hasilnya bahkan mungkin lebih lambat, karena mungkin bukan gaya pengkodean yang dirancang optimis untuk menghadapinya dengan baik - tetapi lebih pintar ;-)
sumber
Di masa lalu ketika komputer memiliki waktu jam diukur dalam mikrodetik, memori diukur dalam kilobyte, dan kompiler primitif, optimasi mikro masuk akal.
Kecepatan dan ukuran komputer generasi saat ini dan kualitas kompiler generasi sekarang berarti bahwa optimasi mikro biasanya membuang-buang waktu. Pengecualiannya cenderung ketika Anda benar-benar harus mendapatkan kinerja maksimum dari beberapa kode intensif komputasi ... atau Anda menulis untuk sistem tertanam dengan sumber daya yang sangat terbatas.
Twitter dan Facebook muncul dalam pikiran :-)
sumber