Optimalisasi kinerja aplikasi PHP
Manfaat terbesar pemrograman PHP adalah betapa mudahnya mempelajari bahasa pemrograman ini dan perpustakaannya yang kaya. Bahkan jika kita tidak tahu banyak tentang fungsi yang perlu kita gunakan, kita bisa menebak bagaimana menyelesaikan tugas tertentu.
Meskipun PHP sangat sederhana dan mudah dipelajari, kita tetap perlu meluangkan sedikit waktu untuk mempelajari beberapa keterampilan pemrograman PHP, terutama yang berkaitan dengan performa dan penggunaan memori. Di PHP, ada banyak trik yang memungkinkan kita mengurangi penggunaan memori dan meningkatkan kinerja aplikasi. Pada artikel kali ini kami akan memperkenalkan secara singkat analisis aplikasi PHP, cara mengubah kode script, dan membandingkan berbagai nilai parameter sebelum dan sesudah optimasi.
Dengan mengatur prosedur waktu dalam program dan mengeksekusi kode-kode ini berulang kali, kita dapat memperoleh sekumpulan data tentang kecepatan eksekusi program. Data ini dapat digunakan untuk menemukan hambatan dalam program dan cara mengoptimalkannya untuk meningkatkan kinerja program aplikasi.
Mungkin pembaca pernah mendengar tentang perpustakaan PEAR. Kami akan menggunakan perpustakaan PEAR untuk membuat contoh yang perlu kami gunakan selama analisis. Ini juga merupakan cara termudah untuk menganalisis kode yang ada.
Nama perpustakaan yang akan kita gunakan adalah PEAR::Benchmark dan sangat berguna untuk pembuatan profil dan pengujian kinerja kode. Pustaka ini menyediakan kelas bernama Benchmark_Timer(), yang dapat mencatat waktu antara satu pemanggilan fungsi dan pemanggilan fungsi berikutnya. Saat menguji performa kode, kita bisa mendapatkan detail hasil eksekusi skrip yang sangat sederhana, sebagai berikut:
include_once("Tolok Ukur/Timer.php");
$bench = Benchmark_Timer baru;
$bangku->mulai();
$bench-> setMarker('Awal skrip');
// Sekarang dalam kondisi tidur selama beberapa menit
tidur(5);
$bangku->berhenti();
// Dapatkan informasi analisis dari pengatur waktu
print_r($bench->getProfiling());
?>
Output setelah mengeksekusi kode di atas adalah sebagai berikut:
Himpunan
(
[0] => Susunan
(
[nama] => Mulai
[waktu] => 1013214253.05751200
[perbedaan] => -
[jumlah] => 0
)
[1] => Susunan
(
[nama] => Awal skrip
[waktu] => 1013214253.05761100
[perbedaan] => 9.8943710327148E-05
[jumlah] => 9.8943710327148E-05
)
[2] => Susunan
(
[nama] => Berhenti
[waktu] => 1013214258.04920700
[perbedaan] => 4.9915959835052
[jumlah] => 4.9916949272156
)
)
Angka-angka di atas mungkin tampak seperti kumpulan angka yang terputus-putus, namun jika ukuran programnya lebih besar, angka-angka ini bisa sangat berguna.
Mungkin sebagian besar pembaca juga dapat menebak bahwa entri pertama dalam array adalah metode sebenarnya untuk memanggil kelas Benchmark_Timer(), misalnya
$bench->start(), $bench->setMarker() dan $bench->stop(). Angka-angka yang terkait dengan entri ini cukup sederhana.
[0] => Susunan
(
[nama] => Mulai
[waktu] => 1013214253.05751200
[perbedaan] => -
[jumlah] => 0
)
Entri waktu mengacu pada stempel waktu UNIX ketika metode start() dari Benchmark_Timer() dipanggil. Entri diff menunjukkan interval waktu antara panggilan ini dan panggilan terakhir. Karena tidak ada panggilan sebelumnya di sini, tanda hubung adalah total entri mengacu pada total waktu kode telah berjalan sejak awal pengujian hingga panggilan khusus ini. Mari kita lihat output dari array berikutnya:
[1] => Susunan
(
[nama] => Awal skrip
[waktu] => 1013214253.05761100
[perbedaan] => 9.8943710327148E-05
[jumlah] => 9.8943710327148E-05
)
Dari angka di atas kita dapat melihat bahwa setelah memanggil $bench->start(), program berjalan selama 9,8943710327148E-05 detik (yaitu, 0,0000989 detik) sebelum memanggil $bench->setMarker(….).
Pengalaman pengujian kinerja nyata
Meskipun contoh di atas bagus, namun sebenarnya bukan contoh yang baik untuk memutuskan cara mengoptimalkan desain kode situs Anda. Di bawah ini saya akan menggunakan pengalaman pribadi saya sebagai teknisi situs web untuk mengilustrasikan cara memecahkan masalah kinerja.
Saya tidak begitu memahami kode yang digunakan oleh situs web, karena dikembangkan selama bertahun-tahun berdasarkan kebutuhan spesifik - satu modul berisi kode konversi situs web, modul lain mencatat penggunaan situs web, dan modul lainnya memiliki kode konversinya sendiri. peran masing-masing. Pengembang utama situs web dan saya sama-sama menyadari bahwa kode situs web perlu dioptimalkan, tetapi kami tidak tahu apa masalahnya.
Untuk menyelesaikan tugas secepat mungkin, saya mulai mempelajari kode skrip utama situs web, dan menambahkan beberapa perintah $bench->setMarker() ke semua kode skrip dan file yang disertakan, lalu menganalisis output dari $bench ->getProfiling(), dan saya terkejut dengan hasilnya. Ternyata masalahnya terletak pada pemanggilan fungsi yang terkait dengan kode konversi untuk mendapatkan nama bahasa tertentu (seperti en untuk bahasa Inggris), yang digunakan ratusan kali. di setiap halaman. Setiap kali fungsi ini dipanggil, kode skrip menanyakan database MySQL untuk mendapatkan nama bahasa sebenarnya dari tabel database.
Jadi kami membuat sistem buffering untuk informasi jenis ini. Hanya dalam 2 hari kerja, kami meningkatkan kinerja sistem secara signifikan, dan jumlah tampilan halaman meningkat sebesar 40% di minggu pertama. Tentu saja, ini hanyalah salah satu contoh bagaimana menganalisis kode dapat meningkatkan kinerja aplikasi Internet atau situs web Internet.
Panggilan fungsi uji kinerja
Meskipun Benchmark_Timer() sangat berguna ketika menganalisis skrip atau halaman web (dan file yang memuatnya), ini tidak ilmiah karena kita harus memuat skrip beberapa kali untuk mendapatkan data yang dianalisis, dan ini tidak spesifik untuk kelas atau fungsi tertentu . ditelepon.
Kelas lain di perpustakaan PEAR::Benchmark yang disebut Benchmark_Iterator dapat menyelesaikan masalah ini dengan sangat baik. Kelas ini dapat menampilkan informasi analisis untuk fungsi atau metode kelas tertentu. Tujuannya agar bisa mendapatkan hasil yang konsisten dari pengujian karena kita tahu bahwa jika kita menjalankan skrip satu kali dan membutuhkan waktu 10 detik untuk dijalankan, bukan berarti selalu membutuhkan waktu 10 detik untuk dijalankan setiap saat.
Apa pun kasusnya, mari kita lihat beberapa contoh:
// Kode untuk terhubung ke database
include_once("DB.php");
$dsn = susunan(
'phptype' => 'mysql',
'hostspec' => 'localhost',
'database' => 'nama_database',
'nama pengguna' => 'nama_pengguna',
'kata sandi' => 'kata sandi'
);
$dbh = DB::sambungan($dsn);
fungsi getCreatedDate($id)
{
global $dbh;
> $stmt = "PILIH tanggal_buat DARI pengguna WHERE id=$id";
// Gunakan PEAR::DB di sini
$tanggal_dibuat = $dbh-> getOne($stmt);
if ((PEAR::isError($tanggal_dibuat)) ||
(kosong($tanggal_dibuat))) {
kembali salah;
} kalau tidak {
kembalikan $tanggal_dibuat;
}
}
include_once 'Benchmark/Iterate.php';
$bench = Benchmark_Iterate baru;
//Jalankan fungsi getDate 10 kali
$bench-> lari(10, 'getCreatedDate', 1);
//Cetak informasi analisis
print_r($bench->get());
?>
Menjalankan kode di atas menghasilkan hasil yang mirip dengan berikut:
Himpunan
(
[1] => 0,055413007736206
[2] => 0,0012860298156738
[3] => 0,0010279417037964
[4] => 0,00093603134155273
[5] => 0,00094103813171387
[6] => 0,00092899799346924
[7] => 0,0010659694671631
[8] => 0,00096404552459717
[9] => 0,0010690689086914
[10] => 0,00093603134155273
[berarti] => 0,0064568161964417
[iterasi] => 10
)
Angka-angka di atas mudah dimengerti. Entri rata-rata mewakili waktu rata-rata 10 kali fungsi getCreatedDate() dijalankan. Dalam pengujian sebenarnya, Anda harus menjalankannya setidaknya 1000 kali, namun hasil dari contoh ini cukup untuk menggambarkan masalahnya.