Tutorial Array Pada PHP
Notasi Big-O
Materi ini memiliki 1 buah lampiran. Namun Anda tidak dapat mengakses lampiran karena belum terdaftar di kursus ini. Klik disini untuk mendaftar.
Nantinya kalau kita sudah membuat situs yang ternyata mendapatkan banyak user, kita akan mendapatkan kasus dimana kode yang sudah kita tulis dengan baik di komputer kita sendiri, ternyata setelah di-upload ke server menyebabkan server berjalan pelan dan bahkan bisa menyebabkan server menjadi down. Hal seperti ini biasanya disebabkan karena penggunaan kode tersebut sudah banyak, dan kode juga digunakan untuk memproses data dengan jumlah banyak sehingga penggunaan resource servernya menjadi banyak pula. Oleh karena itu, ada baiknya pada saat kita menuliskan kode, kita bisa melakukan analisa terhadap logika yang digunakan pada kode.
Salah satu metode untuk menganalisa logika yang sering digunakan adalah notasi big-o. Dengan menggunakan notasi big-o, kita bisa memperkirakan berapa banyak waktu yang bertambah pada saat kode yang sama harus memproses jumlah data yang lebih banyak.
Hal ini penting sekali, terutama untuk pemograman web bagian backend. Karena kalau kode kita berjalan selama 10 detik, berarti kode tersebut menggunakan satu cpu selama 10 detik hanya untuk satu kali proses. Kalau ada banyak user yang menggunakan kode tersebut secara bersamaan, artinya kita memerlukan banyak cpu agar bisa memenuhi kebutuhan para user. Hal ini akan menjadi masalah yang menyebabkan situs kita menjadi lambat, dan perlu kita akali dengan cara seperti mengoptimasi logika yang digunakan agar memerlukan waktu yang lebih sedikit, atau menambah resource cpu server, atau menggunakan antrian untuk mengeksekusi kode.
Notasi Big-O membandingkan berapa banyak jumlah waktu yang diperlukan dengan jumlah data yang bertambah. Kalau kita lihat di grafik sebelah kanan, sumbu horizontal ke arah kanan menunjukkan jumlah data yang bertambah, sedangkan sumbu vertikal ke arah atas menunjukkan jumlah waktu yang diperlukan.
Notasi yang paling baik adalah O(1), dimana kode kita berjalan dengan jumlah waktu yang sama tidak peduli berapa banyak pun datanya. Kode seperti ini bisa kita gunakan untuk memproses milyaran atau bahkan trilliunan data sekaligus tanpa perlu menambah jumlah waktu untuk menjalankan kode. Namun sayangnya hanya sebagain kecil masalah yang bisa dipecahkan menggunakan algoritma O(1).
Sedangkan notasi yang normal adalah notasi O(n). Artinya penambahan jumlah data berbanding lurus dengan penambahan jumlah waktu yang diperlukan untuk memproses data tersebut. Kalau misalkan kode kita memerlukan waktu 1 detik untuk memproses 1.000 data, maka pada saat jumlah datanya dinaikkan 10 kali lipat menjadi 10.000 data, maka jumlah waktu yang diperlukan juga naik 10 kali lipat menjadi 10 detik.
Nah, kebanyakan dari kita berpikir bahwa kode yang kita tulis adalah notasi O(n). Namun kenyataannya tidak begitu. Seringkali kita menuliskan kode dengan notasi O(n^2) atau bahkan lebih jelek, namun kita tidak menyadarinya. Apabila kode kita digunakan untuk jumlah data yang meningkat sepuluh kali lipat, waktu yang diperlukan untuk memproses data tersebut bisa meningkat hingga 100 kali lipat, atau bahkan lebih. Hal seperti inilah yang akan membahayakan penggunaan resource server kita.
Sebagai contoh, kita akan kembali ke source code latihan kita pada video sebelumnya, yaitu latihan bilangan prima.
Kita buka kembali source code dari latihan terakhir. Namun disini saya sudah melakukan modifikasi sedikit ya. Disini saya sudah menambahkan function getPrimes yang berfungsi untuk mencari bilangan prima hingga ke nilai argument $max.
Kita akan menambahkan kode untuk menghitung berapa banyak waktu yang diperlukan untuk eksekusi function getPrimes dengan jumlah data tertentu. Berhubung kita membutuhkan function yang berhubungan dengan waktu, maka kita bisa membuka dokumentasi PHP mengenai Date/Time Functions.
Disini kita bisa melihat bahwa function yang berhubungan dengan waktu adalah function time(). Kita buka dokumentasinya. Function ini mengembalikan sebuah nilai integer atau bilangan bulat, yang merupakan jumlah detik yang telah dilewati setelah tanggal 1 Januari 1970 GMT. Ini adalah cara pencatatan waktu yang digunakan oleh sistem operasi UNIX.
Kita coba ya. Pertama kita komentari dahulu pemanggilan function getPrimes. Lalu kita tambahkan perintah echo time(). Kita jalankan.
Nah, disini kita mendapatkan sebuah bilangan bulat yang menunjukkan berapa detik yang telah dilewati setelah tanggal 1 Januari 1970. Kalau kodenya kita jalankan ulang, maka kita mendapatkan bilangan bulat lagi, dimana digit depannya masih sama dengan yang sebelumnya. Hanya berbeda beberapa digit di belakang saja ya. Kalau kedua nilai ini kita selisihkan, maka kita mendapatkan jumlah detik selisih waktu antara eksekusi kode yang pertama kali dengan eksekusi kode yang kedua.
Namun sayangnya perhitungan waktu per detik ini masih kurang akurat kalau kita gunakan untuk menghitung berapa lama waktu yang diperlukan untuk menjalankan kode kita. Kita kembali ke halaman dokumentasi, dan ternyata masih ada function lain yang bernama microtime().
Kita lihat lagi dokumentasinya, ternyata function microtime() bisa mengembalikan waktu secara lebih akurat hingga ke microsecond. Microsecond disini artinya adalah satu per sejuta detik. Function ini sudah cukup akurat ya untuk kita gunakan mengukur waktu pada video ini.
Kalau teman-teman masih meneruskan untuk membaca dokumentasi, sebenarnya masih ada function yang lebih baru lagi yaitu hrtime() yang bisa mengukur waktu secara lebih akurat hingga ke nanoseconds. Nanoseconds berarti satu per semilyar detik. Disini kita tidak menggunakan hrtime karena cara penggunaan hrtime lebih rumit dan kita tidak memerlukan akurasi hingga nanoseconds.
Kita coba ya. Kita ganti function time menjadi microtime. Disini kita mesti menggunakan argument true agar function mengembalikan nilai berupa float atau bilangan desimal. Kita jalankan. Perhatikan bahwa nilai di depan koma formatnya masih sama dengan function time tadi, yaitu jumlah detik yang berjalan setelah tanggal 1 Januari 1970. Namun di belakang koma kita masih mendapatkan pecahan dengan akurasi hingga satu per sejuta detik.
Sekarang kita gunakan untuk mencatat waktu yang diperlukan untuk menjalankan function getPrimes. Sebelum kita memanggil function getPrimes, kita buat dahulu variable $start untuk mencatat waktu. Setelah kita menjalankan function getPrimes, kita buat lagi variable $end untuk mencatat waktu. Kemudian kita buat variable $duration untuk mencatat waktu yang diperlukan untuk menjalankan function getPrimes, caranya adalah kita kurangi $end dengan $start. Berhubung kita hanya memerlukan pengukuran hingga 3 digit dibelakang koma, maka kita panggil fungsi round dengan argument kedua angka 3. Setelah itu kita echo "Waktu yang diperlukan $duration detik\n".
Kita ubah argument getPrime menjadi 10. Kita coba jalankan. Waktu yang diperlukan hanya sekitar 1 mili detik ya. Kita tingkatkan jumlah datanya menjadi 100. Waktunya berubah menjadi 2 mili detik.
Kita coba lagi ke 1.000. Kemudian 10.000. Nah, disini waktunya udah lumayan banyak berubah ya. Sudah menjadi 0,4 detik. Kalau kita ubah datanya menjadi 100.000. Kita jalankan ya. Kalau menurut teman-teman kira-kira butuh berapa detik? Kalau kita bicara mengenai notasi O(n), seharusnya jumlah pertambahan waktunya sebanding dengan jumlah pertambahan data. Jadi kalau jumlah data meningkat 10 kali lipat, maka jumlah waktunya seharusnya meningkat 10 kali lipat juga menjadi 5 detik.
Namun setelah kita jalankan, ternyata perbedaan waktunya jauh ya. Dari 0,4 detik berubah menjadi 24 detik. Perubahan jumlah data 10 kali lipat bisa menyebabkan perbedaan waktu hingga hampir 60 kali lipat.
Inilah yang disebut dengan notasi O(n^2). Kalau kita lihat pada grafik tadi, notasi O(n^2) berada di bagian merah atau horible alias jelek banget. Kalau function kita digunakan untuk jumlah data yang lebih besar, maka jumlah waktu yang diperlukannya meningkat terlalu banyak.
Bagaimana cara menentukan notasi dari logika yang sedang kita gunakan? Caranya adalah dihitung dari jumlah loopnya. Perhatikan pada function getPrimes kita telah melakukan loop sebanyak jumlah data. Lalu di dalam loop kita memanggil function isPrime dimana kita melakukan loop lagi sebanyak jumlah data. Jadinya notasi yang digunakan adalah O(n^2). Namun disini ada sedikit optimasi ya, karena pada setiap bilangan genap, kita langsung keluar dari function isPrime pada nilai awal i = 2. Makanya peningkatan waktunya tidak separah 100 kali lipat.
Jumlah waktu yang diperlukan untuk eksekusi ini masih bisa ditingkatkan dengan cara melakukan optimasi pada source code. Bagian yang paling perlu diperbaiki adalah jumlah iterasi yang dilakukan. Sebagai contoh pada latihan ini, ternyata untuk memeriksa isPrime kita hanya perlu memeriksa hingga ke akar dari $n.
Kita coba ya. Kita copy paste dahulu function isPrime menjadi isPrime2. Lalu pada kondisi perulangannya kita ubah menjadi $i <= sqrt($n). Kita ubah isi function getPrimes menjadi menggunakan isPrime versi kedua. Dan kita jalankan. Ternyata waktu yang diperlukan berkurang dalam jumlah yang sangat besar ya. Dari dua puluhan detik menjadi hanya satu detik saja. Hal ini terjadi karena kita melakukan optimasi kode dengan cara mengurangi jumlah iterasinya.
Iterasinya juga masih bisa kita kurangi lagi. Kita copy paste lagi menjadi isPrime3. Kita tambahkan kondisi apabila $n == 2 maka kita return true. Kemudian apabila $n habis dibagi 2, maka kita return false. Dan pada saat melakukan perulangan, kita hanya memeriksa bilangan ganjil. Jadi perulangan dimulai dengan nilai awal i = 3. Dan increment-nya adalah i += 2. Kita ubah function getPrimes menjadi menggunakan isPrime versi ketiga dan kita coba jalankan. Kita mendapatkan hasil yang sama dalam waktu yang lebih singkat lagi, yaitu dibawah 1 detik.
Dan sekali lagi optimasi yang kita lakukan adalah mengurangi jumlah iterasi yang dilakukan. Nah, ini adalah versi yang paling optimal untuk algoritma yang sedang kita gunakan. Kalau kita ingin agar waktunya menjadi lebih singkat lagi, maka kita harus mengganti keseluruhan kode agar menggunakan algoritma lain. Sampai disini dulu video kita kali ini. Kita akan bahas lagi latihan ini di video berikutnya.
Dengan menggunakan fasilitas tanya jawab, maka Anda bisa bertanya dan akan dijawab langsung oleh instruktur kursus.
Anda belum terdaftar pada kursus ini sehingga tidak bisa mengajukan pertanyaan.