PHP: array_key_exists mencari 500 kali lebih cepat daripada in_array

Pada 2014, mereka sudah menulis tentang pencarian array , tetapi hampir tidak ada yang mengerti.

Sejak itu, banyak versi PHP telah dirilis dan belum diperbaiki, yang berarti umpan baliknya buruk dan hanya sedikit orang yang tahu. Pada python itu sama, dan dalam 3 * lebih buruk daripada di 2.7.

Kadang-kadang Anda perlu menemukan string dalam array string - operasi yang sangat sering dalam algoritma yang berbeda dan jika array kecil dan terlihat sedikit dan tidak dalam satu lingkaran, maka in_array normal, itu tidak mempengaruhi kecepatan keseluruhan, tetapi jika Anda membutuhkan data besar dan mencari array dari satu miliar baris dan satu miliar kali , maka ini sangat penting: jam lebih baik daripada minggu.

Sebuah acara sederhana tes:

penampilan in_array untuk ideone.com/Yb1mDa 6600msdalam 6-9 detik
dan array_key_exists penampilan untuk hal yang sama, tetapi lebih cepat dari 250 (php5.6 / py3 *.) 400 + kali (php7.3 / py2.7) ideone .com / gwSmFc(siklus meningkat 100 kali) 12ms (6600/12 = 550 kali + -10% spread karena memuat dan cache)

Mengapa ini terjadi? Pertimbangkan secara detail:

1) Menemukan string dalam assembler murni / s adalah mengurutkan array string (cepat atau gelembung), kemudian pencarian biner.

Jumlah langkah dalam log pencarian biner (n) kali tergantung pada ukuran array, dan jauh lebih kecil dari pencarian sederhana.

Anda dapat mengurutkan array string terlebih dahulu, sekali, dan cache, dan kemudian melakukan satu miliar pencarian. Tapi itu tidak membantu.

Secara default, penyortiran terjadi setiap kali lagi, meskipun mereka menulis bahwa mereka meningkat dalam 7.2 in_array melalui hash, tetapi tidak banyak.

2) Cari indeks / kunci (sebagai string) di asosiasi. array / kamus terjadi oleh hash string dan pemrosesan tabrakan. (kesalahan pencarian hash). Hash adalah indeks numerik dari array dan diambil sebagai (alamat elemen nol) + offset * ukuran pointer ke array string dengan hash ini) dalam 2 langkah. + tabrakan brute force, langkah rata-rata kurang dari pencarian biner.
Hash indeks secara otomatis dilakukan sekali sebelumnya saat membuat elemen kamus $ m [key] = val dan di-cache.

Ukuran hash, algoritma hashing dijahit ke mesin php dan tidak dapat diubah, meskipun kode sumber terbuka, Anda dapat mengunduh untuk mengubah dan mengkompilasi jika server Anda.

Anda tidak dapat membaca lebih lanjut, ubah in_array ke array_combine + array_key_exists dan hanya itu.

Jumlah langkah saat mencari berdasarkan hash tergantung pada jumlah tabrakan dan jumlah baris dengan hash yang sama. Mereka perlu disortir atau juga disortir dan pencarian biner.

Untuk mengurangi tabrakan, Anda dapat mengalokasikan lebih banyak memori, jika ada kemungkinan bahwa sekarang bukan masalah 50 tahun yang lalu ketika 1 kb memori pada kumparan magnetik harganya seperti pesawat terbang. Dan saat itulah semua algoritma dasar ditemukan: sort / zip / gif / jpg / etc. - mereka tidak memerlukan banyak memori, tetapi mereka buruk, sekarang mereka jauh lebih baik, tetapi mereka membutuhkan banyak memori 1-16 MB. Ya, ada server dengan 256 MB dan masing-masing memiliki aliran terpisah dan 16 MB sudah banyak, tetapi pada perangkat pengguna rata-rata 1 GB setidaknya dan 16 MB adalah setetes dalam ember.

Efek yang lebih besar dapat diperoleh jika Anda mengganti panggilan ke fungsi array_key_exists dengan konstruksi isset ($ m [key]), itu tidak menghapus antrian perintah dan cache, tidak menggunakan stack, dan lebih cepat di suatu tempat sebesar 20%.

Anda juga dapat mempercepatnya jika Anda membuat array dari 2 huruf pertama - 4 * 16kb dan melihat pertama di offset (indeks = kode karakter 1 + 2 * 256) pointer ke array hash untuk sisa baris, kemudian mencari array kecil "ekor" string. dan tabrakan jauh lebih kecil.

Ini membutuhkan lebih banyak memori dan algoritme lebih rumit, tetapi pencarian 30+ kali lebih cepat. Tetapi ini tidak diimplementasikan dalam php, Anda dapat menulis pustaka begitu / dll dan memanggilnya, atau meminta pengembang untuk menambahkannya di 7.5.

Anda dapat mencari melalui mySQL, tetapi Anda harus mengelompokkan kueri dan itu masih akan lebih lambat.

PS: Metode ini tidak sengaja ditemukan dengan mengetik, intuisi, dan pengalaman ketika saya mempercepat satu situs web besar yang lambat, ada banyak seluk-beluk dan trik, saya berhasil mendapatkan data yang akan diekspor dari 40 detik menjadi 0,8 detik, daftar keluaran dengan penyortiran dan filter, dan banyak lainnya. hal-hal di mana teknik, kerangka kerja dan kerangka kerja standar melakukan semuanya terlalu lambat, meskipun tentu saja mereka nyaman dan mempercepat pengembangan.

All Articles