質問

Gnu Find (" find。")を複製しようとしています。 PHPで使用できますが、速度に近づけることは不可能に思えます。 PHPの実装は、検索の時間の少なくとも2倍を使用します。 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と同じくらい高速であると期待するのはなぜですか?実際には、2倍の速度で実行するだけで十分です。

追加する唯一のアドバイスについては、最初に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回目の試行をチェックポイントできます(たとえば)。ユーザーにファイルのリストを提供している場合は、ページフルを収集してから、ページ2のセッションで残りの状態を保存します。

Jason Cohenが提案したように、 scandir()を使用してディレクトリ全体を一度に読み取ってください。 scandir()

のphpマニュアルコメントのコードに基づいて、次のコードを作成しました。
 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