本文へジャンプ

GIDEON STAFF BLOG

php からのディスクアクセス

php だという時点でアレなんですが…

php からディレクトリにある全ファイルの一覧を取得する処理のパフォーマンスを exec()popen()opendir() を利用した処理で比較してみる。

方法は単純にテスト用のディレクトリに 500 ファイルを用意して、 それぞれの関数を使用してファイル名一覧を取得する処理を 10回実行した場合の処理速度を計測する。

exec("ls -1") 0.774762
popen("ls -1") 0.865914
opendir() 0.136642

外部 shell を実行しないので opendir() が早いだろうとは予想していたが、 これほど差が出るとは思わなかった。
パフォーマンスを優先する場合は勿論だが、 余計なプロセスを生成しないので opendir() が地球に優しい様だ。

<?

	$func = array("byls", "bypopen", "byopendir");

	for($i=0; $i<3; $i++){
		$dist = array();
		$start[$i] = gett();
		for($j=0; $j<100; $j++)
			$dist[$j] = $func[$i]("/tmp/test");
		$end[$i] = gett();

		printf("%-10s:%f\n", $func[$i], $end[$i] - $start[$i]);
	}

	function	byls($dir)
	{

		exec("ls -1 $dir", $output);

		return($output);

	}

	function	bypopen($dir)
	{

		if(($fp = popen("ls -1 $dir", "r"))){
			while($buf = fgets($fp))
				$output[] = trim($buf);
			pclose($fp);

		}

		return($output);

	}

	function	byopendir($dir)
	{

		if($dir = dir($dir)){
			while($file = $dir->read())
				$outout[] = trim($file);
			$dir->close();
		}

	}

	function	gett()
	{

		$t = gettimeofday();
		return((float)($t['sec'] + $t['usec'] / 1000000.0));

	}

?>

ついでにシェルの glob なパターン指定を利用して 指定した文字列にマッチするファイル名の一覧取得を行う場合のテストもしてみた。

20071203000 から 20071203499 までの500個のファイルの中から、 200712032?? にマッチするファイル名の一覧取得で時間を計測してみる。

exec("ls -1 200712032??") 0.883770
popen("ls -1 200712032??") 0.902392
opendir() -> preg_match("/200712032../") 0.188792
glob("/200712032../") 0.203928

exec()popen() が遅いのは相変わらずだが、 preg_match() の呼出しが意外に早かったのが驚き。
正規表現のマッチ処理って基本的に相当時間がかかる筈なんだが…
glob() はファイルシステムに自分でアクセスしてる様なので早い。
複雑なパターン指定が必要なら preg_match() の方が柔軟だが、 シェルに渡せる程度のパターン指定なら glob() を利用するのが 可読性やメンテナンス性と性能が両立できて良いのかも?