Di universitas, di kursus algoritme kami, kami belajar cara menghitung dengan tepat kompleksitas berbagai algoritma sederhana yang digunakan dalam praktik, seperti tabel hash atau pengurutan cepat.
Tapi sekarang dalam proyek perangkat lunak besar, ketika kita ingin membuatnya lebih cepat, yang kita lakukan hanyalah melihat potongan-potongan individual - ada beberapa loop bersarang di sana yang dapat digantikan oleh tabel hash yang lebih cepat, pencarian lambat di sini yang dapat dipercepat oleh teknik yang lebih mewah - tetapi kami tidak pernah menghitung kompleksitas dari seluruh saluran pipa kami.
Apakah ada cara untuk melakukan itu? Atau apakah orang dalam praktik hanya mengandalkan "lokal" menggunakan algoritma cepat, untuk membuat keseluruhan aplikasi lebih cepat, daripada mempertimbangkan aplikasi secara global?
(Karena bagi saya nontrivial menunjukkan bahwa jika Anda menumpuk banyak algoritma yang dikenal sangat cepat sendiri, Anda juga berakhir dengan aplikasi cepat secara keseluruhan.)
Saya menanyakan hal ini, karena saya ditugaskan untuk mempercepat proyek besar yang telah ditulis oleh orang lain, di mana banyak algoritma berinteraksi dan bekerja pada data input, jadi tidak jelas bagi saya bagaimana dampak dari pembuatan algoritma tunggal lebih cepat pada seluruh aplikasi.
sumber
n
meningkat.Jawaban:
Proyek perangkat lunak besar terdiri dari banyak komponen yang berbeda, dan tidak semua dari mereka biasanya menjadi hambatan. Justru sebaliknya: untuk hampir semua program telah melihat dalam hidup saya di mana kinerja rendah adalah masalah, prinsip Pareto diterapkan: lebih dari 80% dari kenaikan kinerja dapat dicapai dengan mengoptimalkan kurang dari 20% dari kode (pada kenyataannya, saya pikir jumlahnya sering lebih dari 95% hingga 5%).
Jadi mulai melihat potongan-potongan individual seringkali merupakan pendekatan terbaik. Itulah sebabnya membuat profil (seperti dijelaskan dalam jawaban David Arno ) baik-baik saja, karena membantu Anda mengidentifikasi 5% kode yang disebutkan di mana pengoptimalan akan memberi Anda "pukulan terbesar untuk uang". Mengoptimalkan "seluruh aplikasi" mengandung risiko overengineering tertentu, dan jika Anda mengoptimalkan 95% itu bahkan dengan faktor 10, seringkali tidak akan memiliki efek yang dapat diukur. Perhatikan juga bahwa pembuatan profil memberi tahu Anda jauh lebih banyak daripada estimasi kompleksitas algoritma hipotetis mana pun, karena algoritme sederhana yang membutuhkan langkah O (N ^ 3) masih bisa lebih cepat daripada algoritme kompleks yang membutuhkan O (N log (N)) selama N cukup kecil.
Setelah profil mengungkapkan titik panas, orang dapat mengoptimalkannya. Tentu saja, "hot spot" bisa lebih besar dari hanya satu atau dua baris kode, kadang-kadang kita harus mengganti seluruh komponen untuk membuatnya lebih cepat, tetapi itu biasanya masih merupakan bagian kecil dari basis kode dalam program yang lebih besar .
Teknik optimisasi khas termasuk
meningkatkan penggunaan algoritma dan struktur data
fine tuning dari mantan
optimasi mikro di beberapa titik panas nyata
pengodean ulang bagian-bagian penting menggunakan kode rakitan atau CUDA
Perhatikan teknik ini bekerja pada berbagai tingkat abstraksi, beberapa dari mereka melihat komponen lebih "secara keseluruhan" daripada yang lain. Jadi itu tergantung pada apa yang Anda maksud dengan "semua yang kita lakukan adalah melihat setiap bagian" - jika Anda hanya memiliki optimasi mikro dalam pikiran, saya tidak setuju bahwa "kami" hanya bekerja pada itu. Tetapi jika Anda bermaksud menerapkan optimasi skala penuh pada bagian atau komponen yang terisolasi, daripada "kami" mungkin bekerja pada bagian yang tepat, dan Anda harus mempertanyakan harapan Anda.
sumber
Cara standar, dicoba dan diuji adalah dengan membuat profil kode . Anda melakukan analisis dinamis dari sistem yang sedang berjalan untuk mengukur timing, penggunaan memori, dll. Kemudian menganalisis hasilnya untuk menemukan hambatan kinerja.
Kemacetan tersebut kemudian secara eksperimental ditulis ulang dan hasilnya diprofilkan sekali lagi untuk menentukan bahwa peningkatan kecepatan, pengurangan penggunaan memori, dll telah tercapai. Proses ini kemudian diulangi hingga perolehan kinerja yang dapat diterima tercapai.
sumber
Meskipun jawaban lainnya benar dan memberikan beberapa panduan, saya pikir mereka melewatkan satu langkah. Dalam sistem yang kompleks seperti yang sedang Anda kerjakan sekarang, memahami berbagai komponen yang membentuk sistem adalah kunci untuk memahami mengapa sesuatu berjalan lambat.
Langkah pertama saya adalah mendapatkan diagram arsitektur rinci atau membuat sendiri. Cari tahu langkah apa yang diambil oleh komponen apa dalam perangkat lunak dan berapa lama setiap langkah.
Juga, cari tahu bagaimana komponen berinteraksi satu sama lain. Ini dapat membuat semua perbedaan.
Sebagai contoh, saya telah melihat kode dalam C # di mana antarmuka antara dua komponen melewati sebuah IEnumerable yang dibangun oleh komponen pertama, yang kemudian disebutkan oleh komponen kedua. Dalam C # ini membutuhkan pengalihan konteks, yang dapat mahal dalam keadaan tertentu. Memecahkannya tidak berdampak pada algoritma. .ToList () yang sederhana pastikan hasilnya dikumpulkan sebelum langkah selanjutnya menyelesaikan masalah ini.
Hal lain yang perlu dipertimbangkan adalah dampak pada sistem Anda menjalankan kode. Interaksi perangkat keras jelas dapat menjadi faktor dalam sistem yang kompleks. Cari IO Disk, alokasi memori besar, dan IO jaringan. Kadang-kadang ini dapat diselesaikan lebih efisien dengan mengutak-atik sistem atau bahkan mengganti perangkat keras.
sumber