Bei Verwendung von xhprof ist mir aufgefallen, dass file_scan_directory()
die Ausführung beim Laden der Startseite mehr als 10 Sekunden dauert. Warum sollte es so lange dauern?
Dies ist die Ausgabe von xhprofile:
Bei Verwendung von xhprof ist mir aufgefallen, dass file_scan_directory()
die Ausführung beim Laden der Startseite mehr als 10 Sekunden dauert. Warum sollte es so lange dauern?
Dies ist die Ausgabe von xhprofile:
Antworten:
Es hört sich so an, als wären Sie von einem bekannten Problem in Drupal 7 betroffen .
Höchstwahrscheinlich treffen Sie auf Vermeiden Sie das erneute Scannen des Modulverzeichnisses, wenn mehrere Module fehlen . Es passiert, wenn in Ihrer Installation einige Module fehlen. Versuchen Sie, Ihre Systemtabelle zu überprüfen:
SELECT name, filename FROM system WHERE type = 'module' AND status = 1 ORDER BY filename
Bereinigen Sie alle Module, die noch aktiviert sind, aber im Dateisystem fehlen.
Insgesamt ist Drupal 7 viel ressourcenschonender und skalierbarer als Drupal 6, abgesehen von einigen unglücklichen Regressionen wie dieser.
Wenn man sich diese Funktionen ansieht, sieht es so aus, als würde ein Modul oder eine einzelne Datei eines Moduls fehlen. Werfen Sie einen Blick auf drupal_get_filename () , es ruft das drupal_system_listing () auf, das diese Funktion aufruft, wenn es die angeforderte Datei nicht finden kann. Fügen Sie eine dpm (func_get_args ()) hinzu, bevor drupal_system_listing () aufgerufen wird. Diese sollte Ihnen mitteilen, welche Datei nicht gefunden wird.
Es gibt mehrere Gründe, warum dieses Problem auftreten kann, und zu meiner großen Bestürzung bin ich jetzt etwas über diese Gründe informiert. Wenn Sie dieses Problem nach dem Upgrade von Drupal Core auf 7.33+ gerade bemerkt haben, kann dies frustrierend sein, dass dies in jedem Modul ein Tippfehler sein kann, selbst wenn Sie dieses Modul nicht aktualisiert haben.
Möglicherweise möchten Sie zuerst nach dem bekannten Fehler suchen, den @Berdir erwähnt, insbesondere wenn Sie kürzlich "nicht verwendete" Module aus der Codebasis entfernt haben. Um herauszufinden, ob Module aktiviert sind, aber aus dem Dateisystem entfernt wurden, können Sie ein Skript wie das hier erwähnte ausführen oder mein Skript verwenden, das für eine Installation mit mehreren Standorten auf einem System mit Drush geschrieben wurde aus dem Drupal-Basisverzeichnis:
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
oder Folgendes:
while read -r file; do [ -f "$file" ] || echo "$file is missing."; done < <(drush sqlq "SELECT filename FROM system WHERE status = 1")
Wenn Sie ein Modul finden, das aus der Codebasis entfernt wurde, befolgen Sie die Anweisungen in den von @Berdir genannten Problemen.
Wenn dies nicht der Fall ist, wird Ihre Situation wahrscheinlich durch einen Codierungsfehler verursacht, z. B. durch eine Datei, die entfernt wurde, aber noch durch einen Aufruf von drupal_add_js (aus Kommentar 19 in Ausgabe # 1082892) oder einen unglücklichen Tippfehler in einem Modul oder Thema hinzugefügt wird zB imagecache_actions
(siehe https://drupal.org/node/2381357 ).
Um genau herauszufinden, warum dies geschieht, müssen Sie in jedem Fall genau wissen, welche Datei Drupal nicht finden kann. So, wie pro Berdir Kommentar, können Sie vorübergehend hacken drupal_get_filename
in bootstrap.inc
durch ein Protokoll oder eine Nachricht Gespräch hinzugefügt wird kurz vor dem Aufruf drupal_system_listing()
. Wenn Sie das Devel-Modul installiert dpm
haben, funktioniert es. Wenn nicht, können Sie drupal_set_message
oder syslog verwenden. Beispiele:
dpm(func_get_args());
drupal_set_message(implode(', ', func_get_args()));
syslog(LOG_WARNING, implode(', ', func_get_args()));
Sobald Sie wissen, wonach Drupal sucht, ist es eine gute Wette, dass Sie herausfinden können, wohin Sie von dort aus gehen müssen. Mein Problem wurde durch einen Aufruf verursacht, eine Datei aus dem nicht vorhandenen Modul aufzunehmen imagcache_actions
(Tippfehler beachten). Also habe ich imagecache_actions
in meiner Codebasis gesucht (z. B. grep -r imagcache_actions .
) und festgestellt, dass Version 1.4 von imagecache_canvasactions.module
module_load_include außerhalb eines Funktionsaufrufs im Dateibereich mit einem Tippfehler verwendet. Auch dieser Fehler wurde erst nach dem Update auf Drupal 7.33+ angezeigt. Ich stellte fest, dass bereits ein Problem für erstellt wurde imagecache_actions
, wendete den Patch an und war wieder im Geschäft.
Ich hatte ein sehr ähnliches Problem - ich habe file_scan_directory()
die Seite getötet. Es stellte sich heraus, dass ein riesiger node_modules
Ordner, der in mein benutzerdefiniertes Design eingebettet gulp
war, bei jedem Cache-Flush gescannt wurde. Das Verschieben dieser Dateien aus dem Themenordner (und das Aktualisieren einiger Pfade in meiner Gulpfile) schien das Problem für mich zu beheben. Alternativ: Ich denke du kannst hacken file.inc
:
'nomask' => '/(\.\.?|CVS|node_modules)$/', // https://www.drupal.org/node/2329453#comment-9360519
Dies file_scan_directory()
ist eine rekursive Funktion, die alle Dateien enthält, die für ein bestimmtes Verzeichnis übereinstimmen. Es sind Verwendungen is_dir()
und opendir()
PHP-Aufrufe, die im Hinblick auf E / A-Systemaufrufe am zeitaufwändigsten sind. Einfacher Drupal-Bootstrap (z. B. time drush ev ""
) kann file_scan_directory
einige tausend Mal aufgerufen werden (abhängig von der Komplexität Ihrer Drupal-Ordnerhierarchie, z. B. Anzahl der Module und ihrer Ordner).
In meinem Fall hatte ich ~ 1500 Anrufe an file_scan_directory
(insgesamt 24 Sekunden, bestehend aus 2 Anrufen von drupal_system_listing
in common.inc
, dann wurden die anderen Anrufe durch rekursive Anrufe an sich file_scan_directory
selbst aufgeteilt.
Um die Leistung bei E / A-Aufrufen zu verbessern, müssen Sie das Datei-Caching implementieren. Dies kann erreicht werden, indem OPCache ( opcache.enable=1
) installiert und aktiviert und seine Einstellungen angepasst werden (siehe: Verwendung von PHP OPCache? ). Es wird auch empfohlen, speicherbasiertes Caching wie memcached / redis zu verwenden.
Wenn Sie eine Befehlszeilenschnittstelle (z. B. drush
) verwenden, sollten Sie diese auch aktivieren opcache.enable_cli=1
.
Nach der Änderung können Sie die aufwendigeren Systemaufrufe mit einigen verfügbaren Debuggern überprüfen.
Z.B
Unter Linux mit strace
(hit Ctrl- Cto finish):
sudo strace -c -fp $(pgrep -n php)
Unter Unix dtrace
(unter Verwendung der statischen DTrace-Sonden von PHP ), z
sudo dtrace -n 'inline string NAME = "php"; syscall:::entry /(NAME == strstr(NAME, execname)) || (execname == strstr(execname, NAME))/ { @num[probefunc] = count(); }'
Sie können die Optimierung drupal_system_listing()
oder file_scan_directory()
Implementierung eines statischen Caches in Betracht ziehen , z
--- 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);
Oder für das Caching von file_scan_directory
Anrufen aus drupal_system_listing()
, dann überprüfen Sie den folgenden Patch verfügbar unter: file_scan_directory zwischengespeichert werden sollen .