PHP bir özyinelemeli dosya tarama hızlandırmak mümkün mü?

8 Cevap php

PHP Gnu Find ("bulmak.") Çoğaltmak için çalışıyorum, ama onun hızına yakın bile almak imkansız görünüyor. PHP uygulamaları en az iki katı Bul arasında zaman kullanabilirsiniz. PHP ile bunu daha hızlı bir yolu var mı?

EDIT: Ben SPL uygulamasını kullanarak bir kod örneği eklendi - performans iteratif yaklaşım eşittir

EDIT2: PHP find ararken aslında yerli PHP uygulama daha yavaş oldu. Ben ne var memnun olmalı sanırım :)

// 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);
}

8 Cevap

PHP sadece düz ve basit C kadar hızlı yapamıyor.

Eğer değişen bir şey başlamadan önce, profile your code.

Yavaş parçalar nerede olduğunu öğrenmek için (güzel bir grafik için artı KCacheGrind) Xdebug gibi bir şey kullanın. Körü körüne şeyler değişiyor başlarsanız, her yerde almazsınız.

Benim sadece diğer tavsiyem zaten yayınlanmıştır olarak SPL dizin yineleyicileri kullanmaktır. İç C kodu işini yapmasına izin hemen hemen her zaman daha hızlıdır.

Ben performansı daha iyi olup olmadığından emin değilim, ama RecursiveDirectoryIterator ve 'SplFileInfo` bak ... kod kolaylaştırmak için bir ardışık dizin yineleyici kullanabilirsiniz.

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

    echo $file->getPathname();
}

kullanmayı deneyin

Örnek: RecursiveDirectoryIterator

man: RecursiveDirectoryIterator

Derlenmiş C sürüm bulmak gibi Neden yorumlanır PHP kodu kadar hızlı olması beklenir? Sadece iki kez yavaş olarak olmak aslında oldukça iyidir.

Ben eklersiniz sadece tavsiye Hakkında sonunda ob_end_clean başında ve ob_get_contents bir ob_start () (), () yapmaktır. İşte might şeyleri hızlandırmak.

Sen N dizin ağacının derinliği açık N dizini akışları tutuyor. Bunun yerine, bir kerede girişlerinin tüm dizinin yetmeyecek okumaya çalışın, ve sonra girdileri üzerinde yineleme. En azından size masanın I / O önbelleklerini kullanımını maksimize edeceğiz.

Sen ciddi sadece GNU find kullanılarak düşünebilirsiniz. O kullanılabilir, ve güvenli modu açık değilse, muhtemelen sadece iyi sonuçları gibi olacak:

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);
}

Ancak çok büyük olduğunu, bazı dizin olması için olabilir, ya bu konuda rahatsız etmek istiyorum etmeyeceğiz. Başka şekillerde yavaşlık itfa göz önünde bulundurun. Sizin ikinci deneme sadece oturumda dizin yığını kaydederek (örneğin) checkpointed olabilir. Eğer kullanıcı dosyaların bir listesini veriyoruz, sadece bir pageful sonra sayfa 2 oturumda devletin kalanını kurtarmak toplamak.

Jason Cohen önerdi olarak, bir kerede bütün dizin okumak için scandir() kullanmayı deneyin. I scandir() için php manuel yorumlardan kodu aşağıdaki kodu tabanlı ettik

 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";
 }