【问题标题】:readdir vs scandirreaddir 与 scandir
【发布时间】:2012-01-31 08:11:44
【问题描述】:

1] 哪个函数更快?
2] 有什么区别?

Differences

1] readdir 返回目录中下一个条目的名称。 Scandir 从目录中返回一个文件和目录数组。

2] readdir 必须打开一个资源句柄,直到所有条目都被读取。 scandir,也许会创建一个包含所有条目的数组并关闭资源句柄?

【问题讨论】:

标签: php


【解决方案1】:

只是得到结果(不做任何事情),readdir 至少更快:

<?php

$count = 10000;

$dir = '/home/brati';

$startScan = microtime(true);
for ($i=0;$i<$count;$i++) {
    $array = scandir($dir);
}
$endScan = microtime(true);


$startRead = microtime(true);
for ($i=0;$i<$count;$i++) {
    $handle = opendir($dir);
    while (false !== ($entry = readdir($handle))) {
        // We do not know what to do
    }
}
$endRead = microtime(true);

echo "scandir: " . ($endScan-$startScan) . "\n";
echo "readdir: " . ($endRead-$startRead) . "\n";

给予:

== RUN 1 ==
scandir: 5.3707950115204
readdir: 5.006147146225

== RUN 2 ==
scandir: 5.4619920253754
readdir: 4.9940950870514

== RUN 3 ==
scandir: 5.5265231132507
readdir: 5.1714680194855

那当然取决于你打算做什么。如果你必须用 scandir() 写另一个循环,它会更慢。

【讨论】:

    【解决方案2】:

    这真的取决于您对数据的处理方式。

    如果您要逐个访问,则应使用readdir,如果您确实需要在内存中拥有条目列表,则应使用scandir

    无论如何,当您要逐项使用它时,将信息复制到内存中是没有意义的。在这种情况下,懒惰的评估绝对是要走的路。

    我想scandir 只是readdir 调用的同一事物的包装器,因此会更慢。

    【讨论】:

      【解决方案3】:

      我知道这个问题现在可能不是实际问题,但附加我已经做了一些测试(如 Aufziehvogel 和 Sayahan),但差别很小 - 在一个包含 1,000,000 个小(几个字节)文件的目录上。

      $dir = dirname(__FILE__) . '/dir';
      
      $startScan = microtime(true);
      $array = scandir($dir);
      for ($i = 0, $j = count($array); $i < $j; $i++) {
          // Code
      }
      $endScan = microtime(true);
      unset($array);
      
      $startRead = microtime(true);
      $handle = opendir($dir);
      while (false !== ($entry = readdir($handle))) {
          // Code
      }
      $endRead = microtime(true);
      unset($handle);
      unset($entry);
      
      $startDir = microtime(true);
      $files = new DirectoryIterator($dir);
      foreach ($files as $file) {
          // Code
      }
      $endDir = microtime(true);
      unset($files);
      
      echo 'scandir:           ', ($endScan - $startScan), PHP_EOL;
      echo 'readdir:           ', ($endRead - $startRead), PHP_EOL;
      echo 'DirectoryIterator: ', ($endDir - $startDir), PHP_EOL;
      

      结果(硬盘):

      scandir:           1.9403479099274
      readdir:           0.79462885856628
      DirectoryIterator: 0.5853099822998
      

      结果(SSD):

      scandir:           0.83593201637268
      readdir:           0.35835003852844
      DirectoryIterator: 0.28022909164429
      

      CPU:AMD A10-4600M APU,带 Radeon(tm) 高清显卡(4 核)
      内存:8G
      PHP:5.6.29

      【讨论】:

      • 这个测试是在 Linux 系统还是 Windows 系统上进行的?
      • 在 Linux Fedora 上,
      【解决方案4】:

      为读取包含大量文件和目录的整个目录树进行了更多时间比较:

      • 调用 filetype()=="dir" 明显快于 is_dir() 调用

      • opendir/readdir 调用比 RecursiveDirectoryIterator 快得多

      • 使用递归调用深度优先或线性构建目录树没有区别

      以上测试是在 Windows 中在本地 SSD、本地 USB 和网络驱动器上执行的,结果一致。在网络驱动器上运行比本地驱动器慢 180 倍 - 尽管有千兆位和其他快速的 ReadyNAS 单元!

      每秒处理的条目数从 115 个(网络驱动器的最慢代码)到 USB 3.0 驱动器的最快代码的近 65000 个 - 当然是由于缓存。

      但是网络驱动器的巨大差异让你想知道在 PHP 中会发生什么,因为简单的 dir 命令和 Linux 中的 ls 在相同的文件上要快得多。

      待续……

      【讨论】:

        【解决方案5】:

        我做了一些测试。 (感谢 Aufziehvogel 的建设)

        $count = 100000;
        
        $dir = dirname(__FILE__);
        
        $startScan = microtime(true);
        for ($i=0;$i<$count;$i++) {
            $array = scandir($dir);
        }
        $endScan = microtime(true);
        
        $startRead = microtime(true);
        for ($i=0;$i<$count;$i++) {
            $handle = opendir($dir);
            while (false !== ($entry = readdir($handle))) {
                // We do not know what to do                    
            }
        }
        $endRead = microtime(true);
        
        $startGlob = microtime(true);
        for ($i=0;$i<$count;$i++) {
            $array3 = glob('*');
        }
        $endGlob = microtime(true);
        
        echo "scandir: " . ($endScan-$startScan) . "\n";
        echo "readdir: " . ($endRead-$startRead) . "\n";
        echo "glob   : " . ($endGlob-$startGlob) . "\n";
        

        Linux 服务器结果:

        scandir: 0.82553291320801
        readdir: 0.91677618026733
        glob   : 0.76309990882874
        

        这源于 4 核(8 线程)intel E3-1240 Cpu linux + Apache 服务器。

        但 Windows Servers 的结果却相反。 Windows + Apache 服务器 - Intel Q8400 4 核(4 线程)

        Windows 服务器结果:

        $count = 10000; // it was on linux 100000 :)
        
        scandir: 0.61557507515
        readdir: 0.614650011063
        glob   : 1.92112612724
        

        (文件夹包括13个文件。如果文件增加,结果可能会有所不同)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-19
          • 2013-01-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多