Ответ 1
file_exists()
должна быть очень недорогой. Также обратите внимание, что file_exists создает собственный кеш, чтобы помочь с производительностью.
При отображении изображений на нашем веб-сайте мы проверяем, существует ли файл с вызовом file_exists()
. Мы возвращаемся к фиктивному изображению, если файл отсутствует.
Однако профилирование показало, что это самая медленная часть генерации наших страниц с file_exists()
размером 1/2 мс для каждого файла. Мы тестируем только 40 или около того файлов, но это все еще нажимает 20 мс на время загрузки страницы.
Может ли кто-нибудь предложить способ ускорить это? Есть ли лучший способ тестирования, если файл присутствует? Если я создаю кеш файл какого-то типа, как мне его синхронизировать.
file_exists()
должна быть очень недорогой. Также обратите внимание, что file_exists создает собственный кеш, чтобы помочь с производительностью.
Использовать абсолютные пути! В зависимости от вашего параметра include_path
PHP проверяет все (!) эти диски, если вы проверяете относительные пути к файлам! Вы можете временно отключить include_path
до проверки существования.
realpath()
делает то же самое, но я не знаю, быстрее ли это.
Но вход/выход доступа к файлам всегда медленный. Доступ к жесткому диску IS медленнее, чем вычисление чего-либо в процессоре, как правило.
Самый быстрый способ проверить наличие локального файла - stream_resolve_include_path():
if (false !== stream_resolve_include_path($s3url)) {
//do stuff
}
Результаты производительности stream_resolve_include_path() vs file_exists():
Test name Repeats Result Performance
stream_resolve 10000 0.051710 sec +0.00%
file_exists 10000 0.067452 sec -30.44%
В тесте используются абсолютные пути. Источник тестирования здесь. Версия PHP:
PHP 5.4.23-1 ~ dotdeb.1 (cli) (построено: 13 декабря 2013 21:53:21)
Copyright (c) 1997-2013 гг. Группа PHP
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
Мы возвращаемся к фиктивному изображению, если файл отсутствует
Если вам просто интересно вернуться к этому фиктивному изображению, вы можете подумать о том, чтобы позволить клиенту согласовать с сервером посредством перенаправления (на фиктивное изображение) на файл-не найден.
Таким образом, у вас будет только небольшое перенаправление и небольшая задержка на стороне клиента. По крайней мере, вы избавитесь от "дорогого" (которого я не знаю), звоните в file_exists
.
Просто мысль.
file_exists()
автоматически кэшируется PHP. Я не думаю, что вы найдете более быструю функцию в PHP, чтобы проверить наличие файла.
Смотрите этот поток.
Создайте процедуру хеширования для оверки файлов в несколько подкаталогов.
filename.jpg → 012345 → /01/23/45.jpg
Кроме того, вы можете использовать mod_rewrite, чтобы вернуть образ заполнителя для запросов в ваш каталог изображений, который 404.
Тесты с PHP 5.6:
0.0012969970 : stream_resolve_include_path + include
0.0013520717 : file_exists + include
0.0013728141 : @include
0.0000281333 : file_exists + include
0.0000319480 : stream_resolve_include_path + include
0.0001471042 : @include
0.0000281333 : file_exists + include
0.0000360012 : stream_resolve_include_path + include
0.0001239776 : @include
Код:
// microtime(true) is less accurate.
function microtime_as_num($microtime){
$time = array_sum(explode(' ', $microtime));
return $time;
}
function test_error_suppression_include ($file) {
$x = 0;
$x = @include($file);
return $x;
}
function test_file_exists_include($file) {
$x = 0;
$x = file_exists($file);
if ($x === true) {
include $file;
}
return $x;
}
function test_stream_resolve_include_path_include($file) {
$x = 0;
$x = stream_resolve_include_path($file);
if ($x !== false) {
include $file;
}
return $x;
}
function run_test($file, $test_name) {
echo $test_name . ":\n";
echo str_repeat('=',strlen($test_name) + 1) . "\n";
$results = array();
$dec = 10000000000; // digit precision as a multiplier
$i = 0;
$j = 0;
$time_start = 0;
$time_end = 0;
$x = -1;
$time = 0;
$time_start = microtime();
$x= test_error_suppression_include($file);
$time_end = microtime();
$time = microtime_as_num($time_end) - microtime_as_num($time_start);
$results[$time*$dec] = '@include';
$i = 0;
$j = 0;
$time_start = 0;
$time_end = 0;
$x = -1;
$time = 0;
$time_start = microtime();
$x= test_stream_resolve_include_path_include($file);
$time_end = microtime();
$time = microtime_as_num($time_end) - microtime_as_num($time_start);
$results[$time * $dec] = 'stream_resolve_include_path + include';
$i = 0;
$j = 0;
$time_start = 0;
$time_end = 0;
$x = -1;
$time = 0;
$time_start = microtime();
$x= test_file_exists_include($file);
$time_end = microtime();
$time = microtime_as_num($time_end) - microtime_as_num($time_start);
$results[$time * $dec ] = 'file_exists + include';
ksort($results, SORT_NUMERIC);
foreach($results as $seconds => $test) {
echo number_format($seconds/$dec,10) . ' : ' . $test . "\n";
}
echo "\n\n";
}
run_test($argv[1],$argv[2]);
Выполнение командной строки:
php test.php '/path/to/existing_but_empty_file.php' 'Existing File'
php test.php '/path/to/non_existing_file.php' 'Invalid File'
php test.php '/path/invalid/non_existing_file.php' 'Invalid Folder'
Если вы проверяете только существующий files
, используйте is_file()
.
file_exists()
проверяет наличие существующего каталога файлов ИЛИ, поэтому, возможно, is_file() может быть немного быстрее.
Я точно не знаю, что вы хотите сделать, но вы можете просто позволить клиенту обрабатывать его.
Все ли они в одном каталоге? Если это так, возможно, стоит получить список файлов и сохранить их в хеше и сравнить с ними, а не со всеми поисками file_exists.
Если вы хотите проверить наличие файла изображения, гораздо быстрее использовать getimagesize!
Быстрее локально и удаленно!
if([email protected]($image_path_or_url)) // False means no imagefile
{
// Do something
}
Как насчет glob()? Но я не уверен, что это быстро.
Я нахожу 1/2ms за звонок очень, очень доступным. Я не думаю, что есть намного более быстрые альтернативы, так как функции файла очень близки к нижним уровням, которые обрабатывают операции с файлами.
Однако вы могли бы написать оболочку file_exists(), которая кэширует результаты в memcache или аналогичный объект. Это должно сократить время до почти ничего в повседневном использовании.
Вы можете сделать cronjob, чтобы периодически создавать список изображений и хранить их в DB/file/BDB/...
Каждые полчаса должно быть хорошо, но обязательно создайте интерфейс к кешу reset в случае добавления/удаления файла.
И затем, также легко запустить find. -mmin -30 -print0 в оболочке и добавить новые файлы.
Когда вы сохраняете файл в папке, если загрузка была успешно выполнена, вы можете сохранить путь к таблице базы данных.
Затем вам просто нужно сделать запрос к базе данных, чтобы найти путь к запрашиваемому файлу.
Я пришел на эту страницу, ища решение, и, похоже, fopen может сделать трюк. Если вы используете этот код, вы можете отключить ведение журнала ошибок для файлов, которые не найдены.
<?php
for ($n=1;$n<100;$n++){
clearstatcache();
[email protected]("files.php","r");
if ($h){
echo "F";
fclose($h);
}else{
echo "N";
}
}
?>
Старый вопрос, я собираюсь добавить здесь ответ. Для php 5.3.8 is_file() (для существующего файла) на порядок быстрее. Для несуществующего файла время почти идентично. Для PHP 5.1 с eaccelerator они немного ближе.
PHP 5.3.8 w и без APC
time ratio (1000 iterations)
Array
(
[3."is_file('exists')"] => 1.00x (0.002305269241333)
[5."is_link('exists')"] => 1.21x (0.0027914047241211)
[7."stream_resolve_inclu"(exists)] => 2.79x (0.0064241886138916)
[1."file_exists('exists')"] => 13.35x (0.030781030654907)
[8."stream_resolve_inclu"(nonexists)] => 14.19x (0.032708406448364)
[4."is_file('nonexists)"] => 14.23x (0.032796382904053)
[6."is_link('nonexists)"] => 14.33x (0.033039808273315)
[2."file_exists('nonexists)"] => 14.77x (0.034039735794067)
)
PHP 5.1 w/eaccelerator
time ratio (1000x)
Array
(
[3."is_file('exists')"] => 1.00x (0.000458002090454)
[5."is_link('exists')"] => 1.22x (0.000559568405151)
[6."is_link('nonexists')"] => 3.27x (0.00149989128113)
[4."is_file('nonexists')"] => 3.36x (0.00153875350952)
[2."file_exists('nonexists')"] => 3.92x (0.00179600715637)
[1."file_exists('exists"] => 4.22x (0.00193166732788)
)
Есть несколько предостережений.
1) Не все "файлы" - это файлы, is_file() тесты для обычных файлов, а не символические ссылки. Поэтому в системе * nix вы не можете уйти просто с помощью is_file(), если не уверены, что имеете дело только с обычными файлами. Для загрузок и т.д. Это может быть справедливое допущение или если сервер основан на ОС Windows, который на самом деле не имеет символических ссылок. В противном случае вам придется протестировать is_file($file) || is_link($file)
.
2) Производительность определенно ухудшается для всех методов, если файл отсутствует и становится примерно равным.
3) Самое большое оговорку. Все методы кэшируют статистику файлов, чтобы ускорить поиск, поэтому, если файл изменяется регулярно или быстро, удаляется, появляется, удаляется, тогда выполняется clearstatcache();
, чтобы обеспечить правильную информацию о существовании файла в кеше. Поэтому я протестировал их. Я оставил все имена файлов и тому подобное. Важно то, что почти все время сходится, за исключением stream_resolve_include, который равен 4 раза. Опять же, на этом сервере есть eaccelerator, поэтому YMMV.
time ratio (1000x)
Array
(
[7."stream_resolve_inclu...;clearstatcache();"] => 1.00x (0.0066831111907959)
[1."file_exists(...........;clearstatcache();"] => 4.39x (0.029333114624023)
[3."is_file(................;clearstatcache();] => 4.55x (0.030423402786255)
[5."is_link(................;clearstatcache();] => 4.61x (0.030798196792603)
[4."is_file(................;clearstatcache();] => 4.89x (0.032709360122681)
[8."stream_resolve_inclu...;clearstatcache();"] => 4.90x (0.032740354537964)
[2."file_exists(...........;clearstatcache();"] => 4.92x (0.032855272293091)
[6."is_link(...............;clearstatcache();"] => 5.11x (0.034154653549194)
)
В принципе, идея состоит в том, что если вы на 100% уверены, что это файл, а не символическая ссылка или каталог, и, по всей вероятности, он будет существовать, а затем используйте is_file()
. Вы увидите определенный выигрыш. Если файл может быть файлом или символической связью в любой момент, то сбой is_file() 14x + is_link() 14x (is_file() || is_link()
) и в итоге будет в 2 раза медленнее. Если существование файла изменяет LOT, используйте stream_resolve_include_path().
Так что это зависит от вашего сценария использования.
Я думаю, что лучший способ - сохранить URL-адрес изображения в базе данных, а затем поместить его в переменную сеанса, особенно когда у вас есть аутентификация. Таким образом, вам не нужно проверять каждый раз, когда страница перезагружается
Я даже не уверен, что это будет быстрее, но похоже, что вы все равно хотите сравнить soooo:
Создайте кеш большого массива всех путей изображения.
$array = array('/path/to/file.jpg' => true, '/path/to/file2.gif' => true);
Обновите кеш ежечасно или ежедневно в зависимости от ваших требований. Вы сделали бы это, используя cron, чтобы запустить PHP script, который будет рекурсивно проходить через каталог файлов для создания массива путей.
Если вы хотите проверить, существует ли файл, загрузите свой кешированный массив и просто проверьте isset() для быстрого поиска индекса массива:
if (isset($myCachedArray[$imgpath])) {
// handle display
}
Потери кэша будут по-прежнему накладными, но он, надеюсь, будет достаточно мал, чтобы оставаться в памяти. Если у вас есть несколько изображений, которые вы просматриваете на странице, вы, вероятно, заметите более значительную прибыль, так как вы можете загрузить кеш при загрузке страницы.