هل من الممكن تسريع عملية فحص الملفات العودية في PHP؟

StackOverflow https://stackoverflow.com/questions/624120

سؤال

لقد كنت أحاول تكرار العثور على جنو ("find .") في PHP، ولكن يبدو من المستحيل الاقتراب من سرعته.تستخدم تطبيقات PHP ضعف وقت البحث على الأقل.هل هناك طرق أسرع للقيام بذلك باستخدام PHP؟

يحرر:لقد أضفت مثالاً للتعليمات البرمجية باستخدام تطبيق SPL - وأدائه يساوي النهج التكراري

تحرير 2:عند استدعاء البحث من PHP، كان في الواقع أبطأ من تطبيق 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 و <لأ href = "http://uk.php.net/SplFileInfo" يختلط = "نوفولو noreferrer"> 'SplFileInfo` .

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

    echo $file->getPathname();
}

قبل أن تبدأ بتغيير أي شيء، ملف التعريف الخاص بك التعليمات البرمجية.

استخدم شيئًا مثل Xdebug (بالإضافة إلى kcachegrind للحصول على رسم بياني جميل) لمعرفة مكان الأجزاء البطيئة.إذا بدأت في تغيير الأشياء بشكل أعمى، فلن تصل إلى أي مكان.

نصيحتي الأخرى الوحيدة هي استخدام مكررات دليل SPL كما تم نشرها بالفعل.إن السماح لرمز C الداخلي بالقيام بالعمل يكون دائمًا أسرع.

وماذا تتوقعون رمز PHP تفسير لتكون كما السريع كإصدار C المترجمة تجد؟ يجري فقط مرتين كما بطيئة هي فعلا جيدة.

وعن النصيحة الوحيدة التي يمكنني أن أضيف هو القيام ob_start () في بداية وob_get_contents ()، ob_end_clean () في نهاية المطاف. أن <م> قد الأشياء بسرعة تصل.

وأنت حفظ الدليل N تيارات مفتوح حيث N هو عمق شجرة الدليل. بدلا من ذلك، حاول قراءة قيمة دليل كامل للإدخالات في آن واحد، ومن ثم تكرار عبر الإدخالات. على الأقل سيكون لتعظيم الاستفادة من مكتب I / O مخابئ.

وأنت قد ترغب في النظر بجدية فقط باستخدام GNU العثور عليها. إذا كان متوفرا، ولا يتم تشغيل الوضع الآمن على، عليك ربما مثل النتائج على ما يرام:

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

ولكن هناك قد يكون بعض الدليل الذي هو كبير جدا، وكنت لا تريد الذهاب الى عناء مع هذا أيضا. النظر في إطفاء بطء بطرق أخرى. محاولة ثانية الخاص بك يمكن checkpointed (على سبيل المثال) ببساطة عن طريق توفير مكدس الدليل في الدورة. إذا كنت تعطي للمستخدم قائمة الملفات، ببساطة جمع pageful ثم حفظ ما تبقى من الدولة في جلسة لصفحة 2.

وحاول استخدام scandir() لقراءة دليل كله في وقت واحد، كما اقترح جايسون كوهين. لقد استند البرمجية التالية على رمز من التعليقات اليدوية بي إتش بي ل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