Frage

Ich habe versucht zu replizieren Gnu finden ( "finden.") In PHP , aber es scheint unmöglich, auch nur annähernd an seine Geschwindigkeit zu bekommen. Die PHP-Implementierungen verwenden mindestens zweimal die Zeit Suche. Gibt es schnellere Wege, dies zu tun mit PHP?

EDIT: Ich habe ein Codebeispiel wird die SPL Implementierung mit - seine Leistung ist gleich dem iterativen Ansatz

EDIT2: Beim Fund von PHP nennt es war tatsächlich langsamer als die native PHP-Implementierung. Ich denke, ich sollte zufrieden sein, was ich habe:)

// measured to 317% of gnu find's speed when run directly from a shell
function list_recursive($dir) { 
  if ($dh = opendir($dir)) {
    while (false !== ($entry = readdir($dh))) {
      if ($entry == '.' || $entry == '..') continue;

      $path = "$dir/$entry";
      echo "$path\n";
      if (is_dir($path)) list_recursive($path);       
    }
    closedir($d);
  }
}

// measured to 315% of gnu find's speed when run directly from a shell
function list_iterative($from) {
  $dirs = array($from);  
  while (NULL !== ($dir = array_pop($dirs))) {  
    if ($dh = opendir($dir)) {    
      while (false !== ($entry = readdir($dh))) {      
        if ($entry == '.' || $entry == '..') continue;        

        $path = "$dir/$entry";        
        echo "$path\n";        
        if (is_dir($path)) $dirs[] = $path;        
      }      
      closedir($dh);      
    }    
  }  
}

// measured to 315% of gnu find's speed when run directly from a shell
function list_recursivedirectoryiterator($path) {
  $it = new RecursiveDirectoryIterator($path);
  foreach ($it as $file) {
    if ($file->isDot()) continue;

    echo $file->getPathname();
  }
}

// measured to 390% of gnu find's speed when run directly from a shell
function list_gnufind($dir) { 
  $dir = escapeshellcmd($dir);
  $h = popen("/usr/bin/find $dir", "r");
  while ('' != ($s = fread($h, 2048))) {
    echo $s;
  }
  pclose($h);
}
War es hilfreich?

Lösung

PHP kann einfach nicht so schnell wie C, schlicht und einfach durchführen.

Andere Tipps

Ich bin nicht sicher, ob die Leistung besser ist, aber man konnte ein rekursive Verzeichnis Iterator verwenden, um Ihren Code einfacher zu machen ... Siehe RecursiveDirectoryIterator und 'SplFileInfo` .

$it = new RecursiveDirectoryIterator($from);
foreach ($it as $file)
{
    if ($file->isDot())
        continue;

    echo $file->getPathname();
}

Bevor Sie etwas beginnen zu ändern, Profil Code .

Verwenden Sie so etwas wie Xdebug (plus kcachegrind für eine hübsche Grafik), um herauszufinden, wo die langsamen Teile sind . Wenn Sie blind Dinge zu verändern beginnen, werden Sie nicht überall bekommen.

Meine einzige andere Beratung ist es, das SPL-Verzeichnis Iteratoren zu verwenden, wie bereits gebucht. Lassen Sie den internen C-Code zu tun die Arbeit fast immer schneller ist.

Warum würden Sie das PHP-Code interpretiert erwarten so schnell wie die kompilierte C-Version zu finden sein? Da er nur doppelt so langsam ist eigentlich ziemlich gut.

über den einzigen Rat, den ich hinzufügen würde, ist eine ob_start () am Anfang und ob_get_contents () zu tun, ob_end_clean () am Ende. Das Macht Dinge zu beschleunigen.

Sie halten N-Verzeichnis-Streams geöffnet, wobei N die Tiefe des Verzeichnisbaums ist. Stattdessen versuchen auf einmal ein ganzes Verzeichnis im Wert von Einträgen zu lesen, und dann über die Einträge iterieren. Zumindest werden Sie Nutzung des Schreibtisches I / O-Caches maximieren.

Vielleicht möchten Sie ernsthaft in Erwägung ziehen nur finden mit GNU. Wenn es verfügbar ist, und abgesicherten Modus nicht eingeschaltet ist, werden Sie wahrscheinlich wie die Ergebnisse ganz gut:

function list_recursive($dir) { 
  $dir=escapeshellcmd($dir);
  $h = popen("/usr/bin/find $dir -type f", "r")
  while ($s = fgets($h,1024)) { 
    echo $s;
  }
  pclose($h);
}

Es könnte jedoch einig Verzeichnis sein, die so groß ist, Sie gehen zu wollen, nicht mit diesem entweder stören. Betrachten wir die Langsamkeit auf andere Weise amortisieren. Ihr zweiter Versuch kann (zum Beispiel) mit Fixpunkten wird, indem man einfach das Verzeichnis Stapel in der Sitzung zu speichern. Wenn Sie den Benutzer eine Liste von Dateien sind zu geben, sammelt einfach ein pageful dann für Seite 2, um den Rest des Staates in der Sitzung speichern.

Versuchen scandir() mit auf einmal ein ganzes Verzeichnis zu lesen, als Jason Cohen vorgeschlagen hat. Ich habe den folgenden Code auf Code aus den PHP-Handbuch Kommentaren zu scandir() Basis

 function scan( $dir ){
        $dirs = array_diff( scandir( $dir ), Array( ".", ".." ));
        $dir_array = Array();
        foreach( $dirs as $d )
            $dir_array[ $d ] = is_dir($dir."/".$d) ? scan( $dir."/".$d) : print $dir."/".$d."\n";
 }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top