Menggunakan xhprof saya perhatikan bahwa file_scan_directory()
membutuhkan lebih dari 10 detik untuk mengeksekusi ketika halaman depan dimuat. Mengapa harus begitu lama?
Ini adalah output dari xhprofile:
Menggunakan xhprof saya perhatikan bahwa file_scan_directory()
membutuhkan lebih dari 10 detik untuk mengeksekusi ketika halaman depan dimuat. Mengapa harus begitu lama?
Ini adalah output dari xhprofile:
Jawaban:
Sepertinya Anda terpengaruh oleh masalah yang diketahui di Drupal 7 .
Kemungkinan besar, Anda menekan Hindari memindai ulang direktori modul ketika beberapa modul hilang . Itu terjadi jika Anda memiliki beberapa modul yang hilang dalam instalasi Anda. Coba periksa tabel sistem Anda:
SELECT name, filename FROM system WHERE type = 'module' AND status = 1 ORDER BY filename
Dan bersihkan semua modul yang masih diaktifkan tetapi hilang dari sistem file.
Secara keseluruhan, Drupal 7 jauh lebih ramah sumber daya dan skalabel dibandingkan Drupal 6, selain beberapa regresi yang kurang menguntungkan seperti ini.
Melihat fungsi-fungsi itu, sepertinya tidak ada modul atau mungkin satu file modul. Lihatlah drupal_get_filename () , ia memanggil drupal_system_listing (), yang memanggil fungsi ini jika tidak dapat menemukan file yang diminta. Tambahkan dpm (func_get_args ()) tepat sebelum memanggil drupal_system_listing (), yang akan memberi tahu Anda file mana yang tidak ditemukannya.
Ada beberapa alasan mengapa masalah ini muncul, dan saya sangat cemas, sekarang saya merasa agak berpengetahuan tentang alasan-alasan itu. Frustasi, jika Anda baru saja melihat masalah ini setelah memutakhirkan Drupal core ke 7.33+, ini bisa menjadi kesalahan ketik pada modul apa pun, bahkan jika Anda belum memutakhirkan modul itu.
Anda mungkin ingin memeriksa bug yang dikenal oleh @Berdir, terutama jika Anda baru saja menghapus modul "tidak terpakai" dari basis kode. Untuk mengetahui apakah Anda memiliki modul yang diaktifkan tetapi telah dihapus dari sistem file, Anda dapat menjalankan skrip seperti yang disebutkan di sini - atau menggunakan milik saya, ditulis untuk instalasi multi-situs pada sistem dengan drush, untuk dijalankan dari direktori basis Drupal:
find sites -maxdepth 1 -iname '*.*' -type d | sed -rne 's:sites/(.+):echo \1; drush @\1 sqlq "select filename from system where status = 1" | grep "/" | sed -rne "s_(.+)_test -f \\1 || echo \\1_p" | bash:p' | bash
atau yang berikut ini:
while read -r file; do [ -f "$file" ] || echo "$file is missing."; done < <(drush sqlq "SELECT filename FROM system WHERE status = 1")
Jika Anda menemukan modul yang telah dihapus dari basis kode, ikuti petunjuk dalam masalah yang disebutkan oleh @Berdir.
Jika bukan itu, situasi Anda kemungkinan disebabkan oleh kesalahan pengkodean, seperti file yang telah dihapus tetapi masih ditambahkan oleh panggilan drupal_add_js (dari komentar 19 dalam edisi # 1082892) atau salah ketik yang salah dalam modul atau tema , mis. imagecache_actions
(lihat https://drupal.org/node/2381357 ).
Bagaimanapun, untuk mencari tahu persis mengapa ini terjadi, Anda perlu tahu persis file mana yang tidak ditemukan oleh Drupal. Jadi, sesuai komentar Berdir, Anda dapat sementara hack drupal_get_filename
di bootstrap.inc
dengan menambahkan log atau pesan panggilan sebelum panggilan untuk drupal_system_listing()
. Jika Anda memiliki modul Devel diinstal maka dpm
akan berfungsi; jika tidak, Anda bisa menggunakan drupal_set_message
atau syslog. Contoh:
dpm(func_get_args());
drupal_set_message(implode(', ', func_get_args()));
syslog(LOG_WARNING, implode(', ', func_get_args()));
Setelah Anda tahu apa yang dicari Drupal, itu adalah taruhan yang bagus bahwa Anda akan dapat mengetahui ke mana harus pergi dari sana. Masalah saya disebabkan oleh panggilan untuk memasukkan file dari modul yang tidak ada imagcache_actions
(perhatikan salah ketik). Jadi, saya mencari imagecache_actions
di basis kode saya (misalnya grep -r imagcache_actions .
), dan menemukan bahwa versi 1.4 imagecache_canvasactions.module
menggunakan module_load_include di luar semua panggilan fungsi, dalam lingkup file, dengan kesalahan ketik. Sekali lagi, kesalahan ini hanya terekspos setelah memperbarui ke Drupal 7.33+. Saya menemukan bahwa masalah telah dibuat untuk imagecache_actions
, menerapkan tambalan, dan kembali berbisnis.
Saya memiliki masalah yang sangat mirip - file_scan_directory()
membunuh situs. Ternyata node_modules
folder huuge yang tertanam di dalam tema khusus saya gulp
sedang dipindai setiap flush cache. Memindahkan file-file ini dari folder tema (dan memperbarui beberapa jalur di gulpfile saya) sepertinya memperbaikinya untuk saya. Atau: Saya pikir Anda bisa meretas file.inc
:
'nomask' => '/(\.\.?|CVS|node_modules)$/', // https://www.drupal.org/node/2329453#comment-9360519
Ini file_scan_directory()
adalah fungsi rekursif yang semua file cocok dengan direktori yang diberikan. Penggunaan is_dir()
dan opendir()
panggilan PHP yang mungkin paling mahal dalam hal panggilan sistem I / O. Bootstrap Drupal sederhana (mis. time drush ev ""
) Dapat memanggil file_scan_directory
beberapa ribu kali (tergantung pada kompleksitas hierarki folder Drupal Anda, mis. Jumlah modul dan foldernya).
Dalam kasus saya, saya memiliki ~ 1500 panggilan ke file_scan_directory
(total 24 detik terdiri dari 2 panggilan dari drupal_system_listing
dalam common.inc
, kemudian panggilan lain dibagi dengan panggilan rekursif ke file_scan_directory
dirinya sendiri.
Untuk meningkatkan kinerja panggilan I / O, Anda perlu menerapkan caching file. Ini dapat dicapai dengan menginstal dan mengaktifkan OPCache ( opcache.enable=1
) dan mengubah pengaturannya (lihat: Cara menggunakan PHP OPCache? ). Menggunakan caching berbasis memori seperti memcached / redis juga disarankan.
Saat menggunakan antarmuka baris perintah (seperti drush
), Anda juga harus mengaktifkan opcache.enable_cli=1
.
Setelah perubahan, Anda dapat memeriksa syscalls yang lebih banyak menggunakan beberapa debugger yang tersedia.
Misalnya
Di Linux menggunakan strace
(tekan Ctrl- Cuntuk menyelesaikan):
sudo strace -c -fp $(pgrep -n php)
On Unix using dtrace
(menggunakan probe statis DTrace PHP ), mis
sudo dtrace -n 'inline string NAME = "php"; syscall:::entry /(NAME == strstr(NAME, execname)) || (execname == strstr(execname, NAME))/ { @num[probefunc] = count(); }'
Anda selanjutnya dapat mempertimbangkan untuk mengoptimalkan drupal_system_listing()
atau file_scan_directory()
dengan menerapkan cache statis, misalnya
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -2104,6 +2104,8 @@ function file_download_access($uri) {
* 'filename', and 'name' members corresponding to the matching files.
*/
function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
+ static $dirs = array();
+
// Merge in defaults.
$options += array(
'nomask' => '/(\.\.?|CVS)$/',
@@ -2120,7 +2122,12 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
if (!preg_match($options['nomask'], $filename) && $filename[0] != '.') {
$uri = "$dir/$filename";
$uri = file_stream_wrapper_uri_normalize($uri);
- if (is_dir($uri) && $options['recurse']) {
+
+ if (empty($dirs[$uri])) {
+ $dirs[$uri] = is_dir($uri);
+ }
+
+ if ($dirs[$uri] && $options['recurse']) {
// Give priority to files in this folder by merging them in after any subdirectory files.
$files = array_merge(file_scan_directory($uri, $mask, $options, $depth + 1), $files);
Atau untuk caching file_scan_directory
panggilan dari drupal_system_listing()
, kemudian periksa tambalan berikut tersedia di: file_scan_directory harus di-cache .