我一直在尝试复制 Gnu Find (“find。”)在PHP中,但似乎不可能接近它的速度。 PHP实现使用至少两倍的Find时间。使用PHP有更快的方法吗?

编辑:我使用SPL实现添加了一个代码示例 - 它的性能等于迭代方法

EDIT2:从PHP调用find时,它实际上比本机PHP实现慢。我想我应该对我所拥有的东西感到满意:)

// 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);
}
有帮助吗?

解决方案

PHP的执行速度不如C,简单明了。

其他提示

我不确定性能是否更好,但您可以使用递归目录迭代器来使代码更简单...请参阅 RecursiveDirectoryIterator 'SplFileInfo`

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

    echo $file->getPathname();
}

在开始更改任何内容之前,对您的代码进行分析

使用像 Xdebug (加上kcachegrind的漂亮图表)来查找慢速部件的位置。如果你盲目地改变事物,你将无法到达任何地方。

我唯一的另一个建议是使用已发布的SPL目录迭代器。让内部C代码完成工作几乎总是更快。

为什么您希望解释的PHP代码与编译的C版本的find一样快?只有两倍的速度实际上非常好。

关于我要添加的唯一建议是在开头做一个ob_start(),在结尾做ob_get_contents(),ob_end_clean()。 可能加快速度。

您将保持N个目录流打开,其中N是目录树的深度。相反,尝试一次读取整个目录的条目,然后迭代条目。至少,您将最大限度地使用桌面I / O缓存。

您可能需要认真考虑使用GNU find。如果它可用,并且安全模式没有打开,你可能会喜欢结果:

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

但是可能有一些目录太大了,你也不想打扰这个。考虑以其他方式缓慢缓慢。您可以通过在会话中保存目录堆栈来检查第二次尝试(例如)。如果您要为用户提供文件列表,只需收集一份页面,然后将剩余的状态保存在第2页的会话中。

尝试使用 scandir()一次读取整个目录,正如Jason Cohen所建议的那样。我的代码来自php代码的代码来自 scandir()

 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";
 }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top